home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / dev / gui / FoxGuiSource.lha / FoxLibSource / FoxGui.c < prev    next >
C/C++ Source or Header  |  2001-07-08  |  163KB  |  5,207 lines

  1. /* FoxGUI - The fast, flexible, free Amiga GUI system
  2.     Copyright (C) 2001 Simon Fox (Foxysoft)
  3.  
  4. This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  5. Foxysoft: www.foxysoft.co.uk      Email:simon@foxysoft.co.uk                */
  6.  
  7. /******************************************************************************
  8.  * Shared library code.  Cannot call functions which use exit() such as:
  9.  * printf(), fprintf()
  10.  *
  11.  * Otherwise:
  12.  * The linker returns "__XCEXIT undefined" and the program will fail.
  13.  * This is because you must not exit() a library!
  14.  *
  15.  * Also:
  16.  * proto/exec.h must be included instead of clib/exec_protos.h and
  17.  * __USE_SYSBASE must be defined.
  18.  *
  19.  * Otherwise:
  20.  * The linker returns "Absolute reference to symbol _SysBase" and the
  21.  * library crashes.  Presumably the same is true for the other protos.
  22.  ******************************************************************************/
  23.  
  24. #define __USE_SYSBASE
  25.  
  26. #include <proto/mathieeedoubbas.h>
  27. #include <stdlib.h>
  28. #include <math.h>
  29. #include <stdarg.h>
  30. #include <ctype.h>
  31. #include <string.h>
  32. #include <time.h>
  33.  
  34. #include <proto/intuition.h>
  35. #include <proto/graphics.h>
  36. #include <proto/exec.h>
  37. #include <proto/console.h>
  38. #include <proto/layers.h>
  39. #include <exec/libraries.h>
  40. #include <exec/memory.h>
  41. #include <graphics/display.h>
  42. #include <graphics/displayinfo.h>
  43.  
  44. #define FOXGUI
  45. #define QRead(a,b)   QueueRead((a)->Con,(b))
  46.  
  47. #include "/FoxInclude/foxgui.h"
  48. #include "FoxGuiTools.h"
  49.  
  50. #define ACTION_BUTTON            1
  51. #define ACTION_TICKBOX            2
  52. #define ACTION_CLOSE                3
  53. #define ACTION_FRAME_LBUT        4
  54. #define ACTION_FRAME_RBUT        5
  55. #define ACTION_RADIO_BUT        6
  56. #define ACTION_LIST_BOX            7
  57. #define ACTION_DRAG_BAR            8
  58. #define ACTION_DROP                9
  59. #define ACTION_RESIZE            10
  60. #define ACTION_WINDOW_DRAG        11
  61. #define ACTION_WINDOW_ACTIVE    12
  62. #define ACTION_EB_RETURN        13
  63. #define ACTION_EB_CLICK_OUT    14
  64. #define ACTION_DISKIN            15
  65. #define ACTION_DISKOUT            16
  66.  
  67. // To respond to the version command.
  68. const char *version = "$VER: FoxGui version 5.1 {c} FoxySoft 1993-2000";
  69.  
  70. static void                        *ActionPtr;
  71. static GuiWindow                *ActionWin;
  72. static short                    Action;
  73. static short                    ActionX, ActionY;
  74. static unsigned long            GuiSecs, GuiMicros;
  75. static unsigned short        *ChipMemForPointer = NULL, *ChipMemForDragPointer = NULL;
  76. static EditBox                    *editptr = NULL, *lastactiveDDListBox = NULL;
  77. static DDListBox                *NewTopBox = NULL;
  78. static BOOL                        ListWinStatusStored = FALSE;
  79. static unsigned long        MenuNum = MENUNULL;
  80. static GuiWindow                *MenuWinPtr = NULL;
  81. static int                        Stop;
  82. struct Library                    *ConsoleDevice = NULL;
  83. static struct IOStdReq        ioreq; // For the console device we're going to use for Rawkey conversions.
  84. static struct InputEvent    *RKCevent;
  85. static unsigned char            *RKCbuffer = NULL; // The buffer for raw key conversions.
  86. static unsigned long            RKCbufferSize = 2;
  87. static BOOL                        EscapeKey;
  88. static GuiWindow                *stModalWin = NULL;
  89. static BOOL                        DragWinFlagsChanged = FALSE;
  90. static ListBoxItem            *SelectedLBHiItem;
  91. static ListBox                    *gDDLastListOver = NULL; // A pointer to the current or last list box under the pointer while dragging data
  92. static ListBoxItem            *gDDLastItemOver = NULL; // A pointer to the current or last list box item under the pointer while dragging data
  93. static TreeControl            *gDDLastTreeOver = NULL; // A pointer to the current or last treecontrol under the pointer while dragging data
  94. static TreeItem                *gDDLastLeafOver = NULL; // A pointer to the current or last tree item under the pointer while dragging data
  95.  
  96. static unsigned long            UserSigMask = 0L;
  97. static void                        *UserSigData = NULL;
  98. static int                        (* __stdargs UserSigFn)(unsigned long signals, void *UserData) = NULL;
  99.  
  100. static DDListBox *DDListBoxItemSelect(BOOL NoSelect, struct ListElement *elemfound);
  101. static DDListBox *NewDDListBoxItemSelect(BOOL NoSelect, struct IntuiText *elemfound);
  102. static BOOL EditBoxSelected(struct IntuiMessage *WinMsg);
  103. static GuiWindow *FindDropWindow(GuiWindow *SourceWindow, short ActionX, short ActionY);
  104. static ListBox *FindDropList(GuiWindow *Target, int ScreenX, int ScreenY);
  105. static Frame *FindDropFrame(GuiWindow *Target, int ScreenX, int ScreenY);
  106. void UndrawTreeControl(TreeControl *tc);
  107. void DrawTreeControl(TreeControl *tc);
  108. void ClearListBoxDropNum(ListBox *lb, ListBoxItem *OldHiItem);
  109. ListBoxItem *SetListBoxDropNum(ListBox *lb, int HiNum, ListBoxItem *OldHiItem);
  110. void ClearTreeControlDropNum(TreeControl *tc, TreeItem *OldHiItem);
  111. TreeItem *SetTreeControlDropNum(TreeControl *tc, TreeItem *HiItem, TreeItem *OldHiItem);
  112. static BOOL CloseGuiScreen(GuiScreen *scr);
  113. static void CloseAllGuiScreens(void);
  114.  
  115. // AutoInitialisation routine.  Called when OpenLibrary is called.  A priority of 4000 means it will happen even
  116. // before global variables are defined (which happens at priority 5000).
  117. // This will cause the IEEE DP Math library to be open for use by all FoxGui functions.
  118. int _STI_4000_InitMath(void)
  119. {
  120.     MathIeeeDoubBasBase = OpenLibrary("mathieeedoubbas.library", 0);
  121.     if (MathIeeeDoubBasBase)
  122.         return 0; //Success
  123.     return -1; //Failure.  OpenLibrary("FoxGui.library", n) will fail.
  124. }
  125.  
  126. // Auto termination function.  Called when the library closes.
  127. void _STD_4000_TermMath(void)
  128. {
  129.     if (MathIeeeDoubBasBase)
  130.         CloseLibrary(MathIeeeDoubBasBase);
  131. }
  132.  
  133. void FOXLIB SetDefaultFont(REGA0 char *name, REGD0 int size, REGD1 int style)
  134. {
  135.     if (GuiFont.ta_Name)
  136.         GuiFree(GuiFont.ta_Name);
  137.     GuiFont.ta_Name = GuiMalloc((strlen(name) + 1) * sizeof(char), 0);
  138.     if (GuiFont.ta_Name)
  139.         strcpy(GuiFont.ta_Name, name);
  140.     GuiULFont.ta_Name = GuiFont.ta_Name;
  141.     GuiFont.ta_YSize = size;
  142.     GuiULFont.ta_YSize = size;
  143.     GuiFont.ta_Style = style;
  144.     GuiULFont.ta_Style = style | FSF_UNDERLINED;
  145. }
  146.  
  147. void FOXLIB GetDefaultFontCopy(REGA0 char *fontname, REGD0 int bufsize, REGA1 int *height, REGA2 int *style)
  148. {
  149.     if (strlen(GuiFont.ta_Name) < bufsize)
  150.         strcpy(fontname, GuiFont.ta_Name);
  151.     else
  152.     {
  153.         strncpy(fontname, GuiFont.ta_Name, bufsize - 1);
  154.         fontname[bufsize - 1] = 0;
  155.     }
  156.     if (height)
  157.         *height = GuiFont.ta_YSize;
  158.     if (style)
  159.         *style = GuiFont.ta_Style;
  160. }
  161.  
  162. void FOXLIB SetDefaultCols(REGD0 int BorderCol, REGD1 int BackCol, REGD2 int TextCol)
  163. {
  164.     Gui.BorderCol = BorderCol;
  165.     Gui.BackCol = BackCol;
  166.     Gui.TextCol = TextCol;
  167. }
  168.  
  169. void GuiSetLastErrAndLine(char *error, char *file, int line)
  170. {
  171.     strcpy(LastErr, error);
  172.     strcpy(LastErrFile, file);
  173.     LastErrLine = line;
  174. }
  175.  
  176. void FOXLIB GuiGetLastErr(REGA0 char *error, REGA1 char *file, REGA2 int *line)
  177. {
  178.     if (LastErrLine > 0)
  179.         strcpy(error, LastErr);
  180.     else
  181.         error[0] = 0;
  182.     if (LastErrLine > 0)
  183.         strcpy(file, LastErrFile);
  184.     else
  185.         file[0] = 0;
  186.     *line = LastErrLine;
  187.     LastErrLine = 0;
  188. }
  189.  
  190. void SetSignals(unsigned long mask, int (*fn)(unsigned long, void*), void *UserData)
  191.     {
  192.     UserSigMask = mask;
  193.     UserSigFn = fn;
  194.     UserSigData = UserData;
  195.     Gui.Done = TRUE;
  196.     }
  197.  
  198. void AddSignals(unsigned long mask)
  199.     {
  200.     UserSigMask |= mask;
  201.     Gui.Done = TRUE;
  202.     }
  203.  
  204. void ClearSignals(unsigned long mask)
  205.     {
  206.     if (mask == 0)
  207.         UserSigMask = 0;
  208.     else
  209.         UserSigMask &= ~mask;
  210.     Gui.Done = TRUE;
  211.     }
  212.  
  213. long FOXLIB GuiTextLength(REGA0 char *text, REGA1 struct TextAttr *font)
  214. {
  215.     struct IntuiText it;
  216.  
  217.     if (font)
  218.         it.ITextFont = font;
  219.     else
  220.         it.ITextFont = &GuiFont;
  221.     it.IText = text;
  222.     it.NextText = NULL;
  223.  
  224.     return IntuiTextLength(&it);
  225. }
  226.  
  227. GuiWindow* FOXLIB GetWindow(REGA0 void *Control)
  228.     {
  229.     void *Parent = NULL;
  230.     // Pretend the control is a frame.  It makes no diffence what type of control we pretend it is.
  231.     Frame *f = (Frame *) Control;
  232.     if (f)
  233.         if (f->WidgetData->ObjectType == ListBoxObject || f->WidgetData->ObjectType == TreeControlObjectType)
  234.             return ((ListBox*) Control)->Win;
  235.         else if (f->WidgetData->ObjectType == OutputBoxObject)
  236.             return ((OutputBox*) Control)->win;
  237.         else if (f->WidgetData->ObjectType == ProgressBarObject)
  238.             return ((ProgressBar*) Control)->win;
  239.         else if (f->WidgetData->ObjectType == WindowObject)
  240.             return (GuiWindow *) Control;
  241.         else if (f->WidgetData->ObjectType == ButtonObject)
  242.             Parent = ((PushButton*) Control)->WidgetData->Parent;
  243.         else if (f->WidgetData->ObjectType == TabControlObject)
  244.             Parent = ((TabControl*) Control)->WidgetData->Parent;
  245.         else if (f->WidgetData->ObjectType == DDListBoxObject)
  246.             Parent = ((DDListBox*) Control)->WidgetData->Parent;
  247.         else if (f->WidgetData->ObjectType == EditBoxObject)
  248.             Parent = ((EditBox*) Control)->WidgetData->Parent;
  249.         else if (f->WidgetData->ObjectType == TickBoxObject)
  250.             Parent = ((TickBox*) Control)->WidgetData->Parent;
  251.         else if (f->WidgetData->ObjectType == RadioButtonObject)
  252.             Parent = ((RadioButton*) Control)->WidgetData->Parent;
  253.         else if (f->WidgetData->ObjectType == FrameObject)
  254.             Parent = ((Frame*) Control)->WidgetData->Parent;
  255.         if (Parent)
  256.             return GetWindow(Parent);
  257.     return NULL;
  258.     }
  259.  
  260. BOOL FOXLIB RegisterGadget(REGA0 struct Gadget *gad, REGA1 GuiWindow *gadwin, REGA2 int (* __far __stdargs gadfn)(struct Gadget*, struct IntuiMessage *))
  261.     {
  262.     if (gad && gadfn)
  263.         {
  264.         UserGadget *ug = (UserGadget*) GuiMalloc(sizeof(UserGadget), 0);
  265.         if (!ug)
  266.             return FALSE;
  267.         ug->next = Gui.FirstUserGadget;
  268.         ug->gad = gad;
  269.         ug->fn = gadfn;
  270.         if (gadwin && ISGUIWINDOW(gadwin))
  271.             ug->win = gadwin;
  272.         else
  273.             ug->win = NULL;
  274.         Gui.FirstUserGadget = ug;
  275.         return TRUE;
  276.         }
  277.     return FALSE;
  278.     }
  279.  
  280. BOOL FOXLIB UnRegisterGadget(REGA0 struct Gadget *gad)
  281.     {
  282.     UserGadget *ug = Gui.FirstUserGadget, *pug = NULL;
  283.     while (ug)
  284.         {
  285.         if (ug->gad == gad)
  286.             {
  287.             if (pug)
  288.                 pug->next = ug->next;
  289.             else
  290.                 Gui.FirstUserGadget = ug->next;
  291.             GuiFree(ug);
  292.             return TRUE;
  293.             }
  294.         pug = ug;
  295.         ug = ug->next;
  296.         }
  297.     return FALSE;
  298.     }
  299.  
  300. BOOL FOXLIB Destroy(REGA0 void *Control, REGD0 BOOL refresh)
  301.     {
  302.     // Pretend the control is a frame.  It makes no diffence what type of control we pretend it is.
  303.     Frame *f = (Frame *) Control;
  304.     if (f)
  305.         {
  306.         if (f->WidgetData->ObjectType == FrameObject)
  307.             DestroyFrame(f, refresh);
  308.         else if (f->WidgetData->ObjectType == ButtonObject)
  309.             DestroyButton((PushButton*) Control, refresh);
  310.         else if (f->WidgetData->ObjectType == TabControlObject)
  311.             DestroyTabControl((TabControl*) Control, refresh);
  312.         else if (f->WidgetData->ObjectType == ListBoxObject || f->WidgetData->ObjectType == TreeControlObjectType)
  313.             return DestroyListBox((ListBox*) Control, refresh);
  314.         else if (f->WidgetData->ObjectType == DDListBoxObject)
  315.             DestroyDDListBox((DDListBox*) Control, refresh);
  316.         else if (f->WidgetData->ObjectType == EditBoxObject)
  317.             DestroyEditBox((EditBox*) Control, refresh);
  318.         else if (f->WidgetData->ObjectType == OutputBoxObject)
  319.             DestroyOutputBox((OutputBox*) Control, refresh);
  320.         else if (f->WidgetData->ObjectType == ProgressBarObject)
  321.             DestroyProgressBar((ProgressBar*) Control, refresh);
  322.         else if (f->WidgetData->ObjectType == TickBoxObject)
  323.             DestroyTickBox((TickBox *) Control, refresh);
  324.         else if (f->WidgetData->ObjectType == RadioButtonObject)
  325.             DestroyRadioButton((RadioButton*) Control, refresh);
  326.         else if (f->WidgetData->ObjectType == WindowObject)
  327.             CloseGuiWindow((GuiWindow*) Control);
  328.         else if (f->WidgetData->ObjectType == ScreenObject)
  329.             return CloseGuiScreen((GuiScreen *) Control);
  330.         else if (f->WidgetData->ObjectType == TimerObject)
  331.             return DestroyTimer((Timer*) Control);
  332.         }
  333.         else
  334.             return FALSE;
  335.     return TRUE;
  336.     }
  337.  
  338. void FOXLIB DestroyM(REGD0 int ObjectType, REGA0 void *Parent, REGD1 BOOL refresh)
  339. {
  340.     GuiWindow *parent = (GuiWindow *) Parent;
  341.  
  342.     if (parent)
  343.     {
  344.         if ((ObjectType == WindowTypeID || ObjectType == 0) && parent->WidgetData->ObjectType == ScreenObject)
  345.             CloseScrWindows((GuiScreen *) Parent);
  346.         if (parent->WidgetData->ObjectType != WindowObject) // Invalid
  347.             return;
  348.         if (ObjectType == FrameTypeID || ObjectType == 0)
  349.             DestroyWinFrames(parent, refresh);
  350.         if (ObjectType == ListBoxTypeID || ObjectType == TreeControlTypeID || ObjectType == 0)
  351.             DestroyWinListBoxes(parent, refresh);
  352.         if (ObjectType == DDListBoxTypeID || ObjectType == 0)
  353.             DestroyWinDDListBoxes(parent, refresh);
  354.         if (ObjectType == EditBoxTypeID || ObjectType == 0)
  355.             DestroyWinEditBoxes(parent, refresh);
  356.         if (ObjectType == ButtonTypeID || ObjectType == 0)
  357.             DestroyWinButtons(parent, refresh);
  358.         if (ObjectType == OutputBoxTypeID || ObjectType == 0)
  359.             DestroyWinOutputBoxes(parent, refresh);
  360.         if (ObjectType == RadioButtonTypeID || ObjectType == 0)
  361.             DestroyWinRadioButtons(parent, refresh);
  362.         if (ObjectType == TickBoxTypeID || ObjectType == 0)
  363.             DestroyWinTickBoxes(parent, refresh);
  364.         if (ObjectType == TabControlTypeID || ObjectType == 0)
  365.             DestroyWinTabControls(parent, refresh);
  366.         if (ObjectType == ProgressBarTypeID || ObjectType == 0)
  367.         {
  368.             ProgressBar *pb = Gui.FirstProgressBar;
  369.             while (pb)
  370.             {
  371.                 ProgressBar *pbn = pb->Next;
  372.                 if (pb->WidgetData->Parent == (Widget*) parent)
  373.                     Destroy(pb, refresh);
  374.                 pb = pbn;
  375.             }
  376.         }
  377.     }
  378.     else
  379.     {
  380.         if (ObjectType == FrameTypeID || ObjectType == 0)
  381.             DestroyAllFrames(refresh);
  382.         if (ObjectType == ListBoxTypeID || ObjectType == TreeControlTypeID || ObjectType == 0)
  383.             DestroyAllListBoxes(refresh);
  384.         if (ObjectType == DDListBoxTypeID || ObjectType == 0)
  385.             DestroyAllDDListBoxes(refresh);
  386.         if (ObjectType == EditBoxTypeID || ObjectType == 0)
  387.             DestroyAllEditBoxes(refresh);
  388.         if (ObjectType == ButtonTypeID || ObjectType == 0)
  389.             DestroyAllButtons(refresh);
  390.         if (ObjectType == OutputBoxTypeID || ObjectType == 0)
  391.             DestroyAllOutputBoxes(refresh);
  392.         if (ObjectType == RadioButtonTypeID || ObjectType == 0)
  393.             DestroyAllRadioButtons(refresh);
  394.         if (ObjectType == TickBoxTypeID || ObjectType == 0)
  395.             DestroyAllTickBoxes(refresh);
  396.         if (ObjectType == TabControlTypeID || ObjectType == 0)
  397.             DestroyAllTabControls(refresh);
  398.         if (ObjectType == ProgressBarTypeID || ObjectType == 0)
  399.         {
  400.             ProgressBar *pb = Gui.FirstProgressBar;
  401.             while (pb)
  402.             {
  403.                 Destroy(pb, refresh);
  404.                 pb = Gui.FirstProgressBar;
  405.             }
  406.         }
  407.         if (ObjectType == TimerTypeID || ObjectType == 0)
  408.             DestroyAllTimers();
  409.         if (ObjectType == WindowTypeID || ObjectType == 0)
  410.             CloseAllWindows();
  411.         if (ObjectType == ScreenTypeID || ObjectType == 0)
  412.             CloseAllGuiScreens();
  413.     }
  414. }
  415.  
  416. void FOXLIB EnableM(REGD0 int ObjectType, REGA0 void *Parent, REGD1 BOOL refresh)
  417. {
  418.     GuiWindow *parent = (GuiWindow *) Parent;
  419.  
  420.     if (parent)
  421.     {
  422.         if (parent->WidgetData->ObjectType != WindowObject) // Invalid
  423.             return;
  424.         if (ObjectType == FrameTypeID || ObjectType == 0)
  425.             EnableWinFrames(parent);
  426.         if (ObjectType == ListBoxTypeID || ObjectType == TreeControlTypeID || ObjectType == 0)
  427.             EnableWinListBoxes(parent);
  428.         if (ObjectType == DDListBoxTypeID || ObjectType == 0)
  429.             EnableWinDDListBoxes(parent, refresh);
  430.         if (ObjectType == EditBoxTypeID || ObjectType == 0)
  431.             EnableWinEditBoxes(parent, refresh);
  432.         if (ObjectType == ButtonTypeID || ObjectType == 0)
  433.             EnableWinButtons(parent);
  434.         if (ObjectType == RadioButtonTypeID || ObjectType == 0)
  435.         {
  436.             RadioButton *rb = Gui.FirstRadioButton;
  437.             while (rb)
  438.             {
  439.                 if (rb->WidgetData->Parent == (Widget*) parent)
  440.                     EnableControl(rb, refresh);
  441.                 rb = rb->Next;
  442.             }
  443.         }
  444.         if (ObjectType == TickBoxTypeID || ObjectType == 0)
  445.         {
  446.             TickBox *tb = Gui.FirstTickBox;
  447.             while (tb)
  448.             {
  449.                 if (tb->WidgetData->Parent == (Widget*) parent)
  450.                     EnableControl(tb, refresh);
  451.                 tb = tb->Next;
  452.             }
  453.         }
  454.         if (ObjectType == TabControlTypeID || ObjectType == 0)
  455.         {
  456.             TabControl *tc = Gui.FirstTabControl;
  457.             while (tc)
  458.             {
  459.                 if (tc->WidgetData->Parent == (Widget*) parent)
  460.                     EnableControl(tc, refresh);
  461.                 tc = tc->next;
  462.             }
  463.         }
  464.         if (ObjectType == ProgressBarTypeID || ObjectType == 0)
  465.         {
  466.             ProgressBar *pb = Gui.FirstProgressBar;
  467.             while (pb)
  468.             {
  469.                 if (pb->WidgetData->Parent == (Widget*) parent)
  470.                     EnableControl(pb, refresh);
  471.                 pb = pb->Next;
  472.             }
  473.         }
  474.     }
  475.     else
  476.     {
  477.         if (ObjectType == FrameTypeID || ObjectType == 0)
  478.             EnableAllFrames();
  479.         if (ObjectType == ListBoxTypeID || ObjectType == TreeControlTypeID || ObjectType == 0)
  480.             EnableAllListBoxes();
  481.         if (ObjectType == DDListBoxTypeID || ObjectType == 0)
  482.             EnableAllDDListBoxes(refresh);
  483.         if (ObjectType == EditBoxTypeID || ObjectType == 0)
  484.             EnableAllEditBoxes(refresh);
  485.         if (ObjectType == ButtonTypeID || ObjectType == 0)
  486.             EnableAllButtons();
  487.         if (ObjectType == RadioButtonTypeID || ObjectType == 0)
  488.         {
  489.             RadioButton *rb = Gui.FirstRadioButton;
  490.             while (rb)
  491.             {
  492.                 EnableControl(rb, refresh);
  493.                 rb = rb->Next;
  494.             }
  495.         }
  496.         if (ObjectType == TickBoxTypeID || ObjectType == 0)
  497.         {
  498.             TickBox *tb = Gui.FirstTickBox;
  499.             while (tb)
  500.             {
  501.                 EnableControl(tb, refresh);
  502.                 tb = tb->Next;
  503.             }
  504.         }
  505.         if (ObjectType == TabControlTypeID || ObjectType == 0)
  506.         {
  507.             TabControl *tc = Gui.FirstTabControl;
  508.             while (tc)
  509.             {
  510.                 EnableControl(tc, refresh);
  511.                 tc = tc->next;
  512.             }
  513.         }
  514.         if (ObjectType == ProgressBarTypeID || ObjectType == 0)
  515.         {
  516.             ProgressBar *pb = Gui.FirstProgressBar;
  517.             while (pb)
  518.             {
  519.                 EnableControl(pb, refresh);
  520.                 pb = pb->Next;
  521.             }
  522.         }
  523.         if (ObjectType == TimerTypeID || ObjectType == 0)
  524.         {
  525.             Timer *t = Gui.FirstTimer;
  526.             while (t)
  527.             {
  528.                 UnpauseTimer(t);
  529.                 t = t->NextTimer;
  530.             }
  531.         }
  532.         if (ObjectType == WindowTypeID || ObjectType == 0)
  533.         {
  534.             GuiWindow *gw = Gui.GWLfirst;
  535.             while (gw)
  536.             {
  537.                 WakePointer(gw);
  538.                 gw = gw->next;
  539.             }
  540.         }
  541.     }
  542. }
  543.  
  544. void FOXLIB DisableM(REGD0 int ObjectType, REGA0 void *Parent, REGD1 BOOL refresh)
  545. {
  546.     GuiWindow *parent = (GuiWindow *) Parent;
  547.  
  548.     if (parent)
  549.     {
  550.         if (parent->WidgetData->ObjectType != WindowObject) // Invalid
  551.             return;
  552.         if (ObjectType == FrameTypeID || ObjectType == 0)
  553.             DisableWinFrames(parent);
  554.         if (ObjectType == ListBoxTypeID || ObjectType == TreeControlTypeID || ObjectType == 0)
  555.             DisableWinListBoxes(parent);
  556.         if (ObjectType == DDListBoxTypeID || ObjectType == 0)
  557.             DisableWinDDListBoxes(parent, refresh);
  558.         if (ObjectType == EditBoxTypeID || ObjectType == 0)
  559.             DisableWinEditBoxes(parent, refresh);
  560.         if (ObjectType == ButtonTypeID || ObjectType == 0)
  561.             DisableWinButtons(parent);
  562.         if (ObjectType == RadioButtonTypeID || ObjectType == 0)
  563.         {
  564.             RadioButton *rb = Gui.FirstRadioButton;
  565.             while (rb)
  566.             {
  567.                 if (rb->WidgetData->Parent == (Widget*) parent)
  568.                     DisableControl(rb, refresh);
  569.                 rb = rb->Next;
  570.             }
  571.         }
  572.         if (ObjectType == TickBoxTypeID || ObjectType == 0)
  573.         {
  574.             TickBox *tb = Gui.FirstTickBox;
  575.             while (tb)
  576.             {
  577.                 if (tb->WidgetData->Parent == (Widget*) parent)
  578.                     DisableControl(tb, refresh);
  579.                 tb = tb->Next;
  580.             }
  581.         }
  582.         if (ObjectType == TabControlTypeID || ObjectType == 0)
  583.         {
  584.             TabControl *tc = Gui.FirstTabControl;
  585.             while (tc)
  586.             {
  587.                 if (tc->WidgetData->Parent == (Widget*) parent)
  588.                     DisableControl(tc, refresh);
  589.                 tc = tc->next;
  590.             }
  591.         }
  592.         if (ObjectType == ProgressBarTypeID || ObjectType == 0)
  593.         {
  594.             ProgressBar *pb = Gui.FirstProgressBar;
  595.             while (pb)
  596.             {
  597.                 if (pb->WidgetData->Parent == (Widget*) parent)
  598.                     DisableControl(pb, refresh);
  599.                 pb = pb->Next;
  600.             }
  601.         }
  602.     }
  603.     else
  604.     {
  605.         if (ObjectType == FrameTypeID || ObjectType == 0)
  606.             DisableAllFrames();
  607.         if (ObjectType == ListBoxTypeID || ObjectType == TreeControlTypeID || ObjectType == 0)
  608.             DisableAllListBoxes();
  609.         if (ObjectType == DDListBoxTypeID || ObjectType == 0)
  610.             DisableAllDDListBoxes(refresh);
  611.         if (ObjectType == EditBoxTypeID || ObjectType == 0)
  612.             DisableAllEditBoxes(refresh);
  613.         if (ObjectType == ButtonTypeID || ObjectType == 0)
  614.             DisableAllButtons();
  615.         if (ObjectType == RadioButtonTypeID || ObjectType == 0)
  616.         {
  617.             RadioButton *rb = Gui.FirstRadioButton;
  618.             while (rb)
  619.             {
  620.                 DisableControl(rb, refresh);
  621.                 rb = rb->Next;
  622.             }
  623.         }
  624.         if (ObjectType == TickBoxTypeID || ObjectType == 0)
  625.         {
  626.             TickBox *tb = Gui.FirstTickBox;
  627.             while (tb)
  628.             {
  629.                 DisableControl(tb, refresh);
  630.                 tb = tb->Next;
  631.             }
  632.         }
  633.         if (ObjectType == TabControlTypeID || ObjectType == 0)
  634.         {
  635.             TabControl *tc = Gui.FirstTabControl;
  636.             while (tc)
  637.             {
  638.                 DisableControl(tc, refresh);
  639.                 tc = tc->next;
  640.             }
  641.         }
  642.         if (ObjectType == ProgressBarTypeID || ObjectType == 0)
  643.         {
  644.             ProgressBar *pb = Gui.FirstProgressBar;
  645.             while (pb)
  646.             {
  647.                 DisableControl(pb, refresh);
  648.                 pb = pb->Next;
  649.             }
  650.         }
  651.         if (ObjectType == TimerTypeID || ObjectType == 0)
  652.         {
  653.             Timer *t = Gui.FirstTimer;
  654.             while (t)
  655.             {
  656.                 PauseTimer(t);
  657.                 t = t->NextTimer;
  658.             }
  659.         }
  660.         if (ObjectType == WindowTypeID || ObjectType == 0)
  661.         {
  662.             GuiWindow *gw = Gui.GWLfirst;
  663.             while (gw)
  664.             {
  665.                 SleepPointer(gw);
  666.                 gw = gw->next;
  667.             }
  668.         }
  669.     }
  670. }
  671.  
  672. void FOXLIB EnableControl(REGA0 void *Control, REGD0 BOOL refresh)
  673.     {
  674.     // Pretend the control is a frame.  It makes no diffence what type of control we pretend it is.
  675.     Frame *f = (Frame *) Control;
  676.     if (f)
  677.         if (f->WidgetData->ObjectType == ButtonObject)
  678.             EnableButton((PushButton*) Control);
  679.         else if (f->WidgetData->ObjectType == FrameObject)
  680.             EnableFrame(f);
  681.         else if (f->WidgetData->ObjectType == TabControlObject)
  682.             EnableTabControl((TabControl*) Control);
  683.         else if (f->WidgetData->ObjectType == ListBoxObject)
  684.             EnableListBox((ListBox*) Control);
  685.         else if (f->WidgetData->ObjectType == DDListBoxObject)
  686.             EnableDDListBox((DDListBox*) Control, refresh);
  687.         else if (f->WidgetData->ObjectType == EditBoxObject)
  688.             EnableEditBox((EditBox*) Control, refresh);
  689.         else if (f->WidgetData->ObjectType == TickBoxObject)
  690.             EnableTickBox((TickBox*) Control);
  691.         else if (f->WidgetData->ObjectType == RadioButtonObject)
  692.             EnableRadioButton((RadioButton*) Control);
  693.         else if (f->WidgetData->ObjectType == WindowObject)
  694.             WakePointer((GuiWindow*) Control);
  695.         else if (f->WidgetData->ObjectType == TimerObject)
  696.             UnpauseTimer((Timer*) Control);
  697.         else if (f->WidgetData->ObjectType == OutputBoxObject || f->WidgetData->ObjectType == ProgressBarObject ||
  698.                 f->WidgetData->ObjectType == ScreenObject)
  699.             {}
  700.     }
  701.  
  702. void FOXLIB DisableControl(REGA0 void *Control, REGD0 BOOL refresh)
  703.     {
  704.     // Pretend the control is a frame.  It makes no diffence what type of control we pretend it is.
  705.     Frame *f = (Frame *) Control;
  706.     if (f)
  707.         if (f->WidgetData->ObjectType == ButtonObject)
  708.             DisableButton((PushButton*) Control);
  709.         else if (f->WidgetData->ObjectType == FrameObject)
  710.             DisableFrame(f);
  711.         else if (f->WidgetData->ObjectType == TabControlObject)
  712.             DisableTabControl((TabControl*) Control);
  713.         else if (f->WidgetData->ObjectType == ListBoxObject)
  714.             DisableListBox((ListBox*) Control);
  715.         else if (f->WidgetData->ObjectType == DDListBoxObject)
  716.             DisableDDListBox((DDListBox*) Control, refresh);
  717.         else if (f->WidgetData->ObjectType == EditBoxObject)
  718.             DisableEditBox((EditBox*) Control, refresh);
  719.         else if (f->WidgetData->ObjectType == TickBoxObject)
  720.             DisableTickBox((TickBox*) Control);
  721.         else if (f->WidgetData->ObjectType == RadioButtonObject)
  722.             DisableRadioButton((RadioButton*) Control);
  723.         else if (f->WidgetData->ObjectType == WindowObject)
  724.             SleepPointer((GuiWindow*) Control);
  725.         else if (f->WidgetData->ObjectType == TimerObject)
  726.             PauseTimer((Timer*) Control);
  727.         else if (f->WidgetData->ObjectType == OutputBoxObject || f->WidgetData->ObjectType == ProgressBarObject ||
  728.                 f->WidgetData->ObjectType == ScreenObject)
  729.             {}
  730.     }
  731.  
  732. BOOL FOXLIB Hide(REGA0 void *Control)
  733.     {
  734.     // Pretend the control is a frame.  It makes no diffence what type of control we pretend it is.
  735.     BOOL retval = FALSE;
  736.     Frame *f = (Frame *) Control;
  737.     if (f)
  738.         {
  739.         Frame *child = f->WidgetData->ChildWidget;
  740.  
  741.         if (f->WidgetData->ObjectType == FrameObject)
  742.             retval = HideFrame(f);
  743.         else if (f->WidgetData->ObjectType == ButtonObject)
  744.             retval = HideButton((PushButton*) Control);
  745.         else if (f->WidgetData->ObjectType == TabControlObject)
  746.             retval = HideTabControl((TabControl*) Control);
  747.         else if (f->WidgetData->ObjectType == ListBoxObject)
  748.             retval = HideListBox((ListBox*) Control);
  749.         else if (f->WidgetData->ObjectType == DDListBoxObject)
  750.             retval = HideDDListBox((DDListBox*) Control);
  751.         else if (f->WidgetData->ObjectType == EditBoxObject)
  752.             retval = HideEditBox((EditBox*) Control);
  753.         else if (f->WidgetData->ObjectType == OutputBoxObject)
  754.             retval = HideOutputBox((OutputBox*) Control);
  755.         else if (f->WidgetData->ObjectType == ProgressBarObject)
  756.             retval = HideProgressBar((ProgressBar*) Control);
  757.         else if (f->WidgetData->ObjectType == TickBoxObject)
  758.             retval = HideTickBox((TickBox*) Control);
  759.         else if (f->WidgetData->ObjectType == RadioButtonObject)
  760.             retval = HideRadioButton((RadioButton*) Control);
  761.         else if (f->WidgetData->ObjectType == WindowObject || f->WidgetData->ObjectType == ScreenObject || f->WidgetData->ObjectType == TimerObject)
  762.             {}
  763.         // Now we've hidden it, see if there are any other controls that form part of the
  764.         // same control and, if so, hide them (e.g. pre/post text).
  765.         while (child)
  766.             {
  767.             if (child->WidgetData->ParentControl == f)
  768.                 retval = retval && Hide(child);
  769.             child = child->WidgetData->NextWidget;
  770.             }
  771.         }
  772.     return retval;
  773.     }
  774.  
  775. BOOL FOXLIB Show(REGA0 void *Control)
  776.     {
  777.     // Pretend the control is a frame.  It makes no diffence what type of control we pretend it is.
  778.     Frame *f = (Frame *) Control;
  779.     BOOL retval = FALSE;
  780.     if (f)
  781.         {
  782.         Frame *child = f->WidgetData->ChildWidget;
  783.  
  784.         if (f->WidgetData->ObjectType == FrameObject)
  785.             retval = ShowFrame(f);
  786.         else if (f->WidgetData->ObjectType == ButtonObject)
  787.             retval = ShowButton((PushButton*) Control);
  788.         else if (f->WidgetData->ObjectType == TabControlObject)
  789.             retval = ShowTabControl((TabControl*) Control);
  790.         else if (f->WidgetData->ObjectType == ListBoxObject)
  791.             retval = ShowListBox((ListBox*) Control);
  792.         else if (f->WidgetData->ObjectType == DDListBoxObject)
  793.             retval = ShowDDListBox((DDListBox*) Control);
  794.         else if (f->WidgetData->ObjectType == EditBoxObject)
  795.             retval = ShowEditBox((EditBox*) Control);
  796.         else if (f->WidgetData->ObjectType == OutputBoxObject)
  797.             retval = ShowOutputBox((OutputBox*) Control);
  798.         else if (f->WidgetData->ObjectType == ProgressBarObject)
  799.             retval = ShowProgressBar((ProgressBar*) Control);
  800.         else if (f->WidgetData->ObjectType == TickBoxObject)
  801.             retval = ShowTickBox((TickBox*) Control);
  802.         else if (f->WidgetData->ObjectType == RadioButtonObject)
  803.             retval = ShowRadioButton((RadioButton*) Control);
  804.         else if (f->WidgetData->ObjectType == WindowObject || f->WidgetData->ObjectType == ScreenObject || f->WidgetData->ObjectType == TimerObject)
  805.             {}
  806.         // Now we've shown it, see if there are any other controls that form part of the
  807.         // same control and, if so, show them (e.g. pre/post text).
  808.         while (child)
  809.             {
  810.             if (child->WidgetData->ParentControl == f)
  811.                 retval = retval && Show(child);
  812.             child = child->WidgetData->NextWidget;
  813.             }
  814.         }
  815.     return retval;
  816.     }
  817.  
  818. /*    This function deactivates a string gadget in the only way that works properly on an A500.  It fakes
  819.     a return key press in the gadget (DeActivateStrGad()) and then clears the window's message port so
  820.     that the GadgetUp message for the gadget is never seen by our message loop. */
  821. void DeactivateUnknownEditBox(void)
  822.     {
  823.     unsigned long signals;
  824.  
  825.     struct Gadget *g;
  826.     GuiWindow *w = Gui.GWLfirst;
  827.  
  828.     while (w)
  829.         {
  830.         g = w->Win->FirstGadget;
  831.         while (g)
  832.             {
  833.             if (g->GadgetType == GTYP_STRGADGET && g->Flags & GFLG_SELECTED)
  834.                 {
  835.                 DeActivateStrGad(); // Will cause a gadgetup message
  836.                 signals = Wait(w->WindowSig);
  837.  
  838.                 if (signals & w->WindowSig)
  839.                     {
  840.                     struct IntuiMessage *WinMsg;
  841.                     while (WinMsg = (struct IntuiMessage *) GetMsg(w->Win->UserPort))
  842.                         ReplyMsg((struct Message *) WinMsg);
  843.                     }
  844.                 }
  845.             g = g->NextGadget;
  846.             }
  847.         w = w->next;
  848.         }
  849.     }
  850.  
  851. BOOL FOXLIB SetEditBoxFocus(REGA0 EditBox *p)
  852.    {
  853.     if (p && p->enabled && p->hidden == 0)
  854.         {
  855.         BOOL retval;
  856.  
  857.         DeactivateUnknownEditBox();
  858.         retval = ActivateGadget(&p->editbox, ((GuiWindow *) p->editbox.UserData)->Win, NULL);
  859.         /*    Set editptr so that the EditBoxSelected() function (which was probably where the user's validation
  860.             function which called this was called from) knows that the user's already put the focus where they
  861.             want it. */
  862.         editptr = p;
  863.         return Diagnostic("SetEditBoxFocus", EXIT, retval);
  864.         }
  865.     return Diagnostic("SetEditBoxFocus", EXIT, FALSE);
  866.     }
  867.  
  868. /*    Convert RAWKEYs into VANILLAKEYs, also shows special keys like HELP, Cursor Keys, FKeys, etc.  It
  869.     returns -1 if not enough room in the buffer, try again with a bigger buffer otherwise, returns the
  870.     number of characters placed in the buffer. */
  871. static long deadKeyConvert(struct IntuiMessage *msg, unsigned char *kbuffer, long kbsize,
  872.         struct KeyMap *kmap, struct InputEvent *ievent)
  873.     {
  874.     ievent->ie_Class = IECLASS_RAWKEY;
  875.     ievent->ie_Code = msg->Code;
  876.     ievent->ie_Qualifier = msg->Qualifier;
  877.     ievent->ie_position.ie_addr = *((APTR*)msg->IAddress);
  878.  
  879.     return(RawKeyConvert(ievent, kbuffer, kbsize, kmap));
  880.     }
  881.  
  882. // doKeys() - Show what keys were pressed.
  883. static BOOL GetConvertedKeys(struct IntuiMessage *msg, unsigned short *numchars)
  884.     {
  885.     BOOL ret_code = TRUE;
  886.  
  887. /* deadKeyConvert() returns -1 if there was not enough space in the buffer to convert the string. Here,
  888.     the routine increases the size of the buffer on the fly...Set the return code to FALSE on failure. */
  889.  
  890.     *numchars = deadKeyConvert(msg, RKCbuffer, RKCbufferSize - 1, NULL, RKCevent);
  891.     while (*numchars == -1 && RKCbuffer)
  892.         {
  893.         // Conversion failed, buffer too small. try to double the size of the buffer.
  894.         GuiFree(RKCbuffer);
  895.         RKCbufferSize = RKCbufferSize << 1;
  896.  
  897.         if (NULL == (RKCbuffer = (unsigned char*) GuiMalloc(RKCbufferSize, MEMF_CLEAR)))
  898.             ret_code = FALSE;
  899.         else
  900.             *numchars = deadKeyConvert(msg, RKCbuffer, RKCbufferSize - 1, NULL, RKCevent);
  901.         }
  902.  
  903. /* numchars contains the number of characters placed within the buffer.  Key up events and   
  904.     key sequences that do not generate any data for the program (like deadkeys) will return   
  905.     zero.  Special keys (like HELP, the cursor keys, FKeys, etc.) return multiple characters  
  906.     that have to then be parsed by the application.  Allocation failed above if buffer is NULL */
  907.  
  908. /*    if (RKCbuffer)
  909.         {
  910.         unsigned char realc, c;
  911.         unsigned short char_pos;
  912.  
  913.         // if high bit set, then this is a key up otherwise this is a key down
  914.         if (msg->Code & 0x80)
  915.             fprintf(stderr, "Key Up:   ");
  916.         else
  917.             fprintf(stderr, "Key Down: ");
  918.  
  919.         fprintf(stderr, " rawkey #%d maps to %d ASCII character(s)\n", 0x7F & msg->Code, *numchars);
  920.  
  921.         for (char_pos = 0; char_pos < *numchars; char_pos++)
  922.             {
  923.             realc = c = RKCbuffer[char_pos];
  924.             if (c <= 0x1F || (c >= 0x80 && c < 0xa0))
  925.                 c = 0x7f;
  926.             fprintf(stderr, "  %3d ($%02x) = %c\n", realc, realc, c);
  927.             }
  928.         } */
  929.     return(ret_code);
  930.     }
  931.  
  932. #ifdef NEVER
  933. struct IntuiMessage ActivateMessage;
  934. static void SendActivateMessage(EditBox *e)
  935.     {
  936.     fprintf(stderr, "Sending message...\n");
  937.     ActivateMessage.ExecMessage.mn_Node.ln_Type = 5;
  938.     ActivateMessage.ExecMessage.mn_Node.ln_Pri = 0;
  939.     ActivateMessage.ExecMessage.mn_Node.ln_Name = "Simon woz ere";
  940.     ActivateMessage.ExecMessage.mn_ReplyPort = e->win->Win->WindowPort;
  941.     ActivateMessage.ExecMessage.mn_Length = 32;
  942.     ActivateMessage.Class = GADGETDOWN;
  943.     ActivateMessage.Code = 0;
  944.     ActivateMessage.Qualifier = 49152;
  945.     ActivateMessage.IAddress = &(e->editbox);
  946.     ActivateMessage.MouseX = e->x + 1;
  947.     ActivateMessage.MouseY = e->y + 1;
  948.     ActivateMessage.IDCMPWindow = e->win->Win;
  949.     ActivateMessage.SpecialLink = NULL;
  950.     CurrentTime(&(ActivateMessage.Seconds), &(ActivateMessage.Micros));
  951.     Forbid();
  952.     PutMsg(e->win->Win->UserPort, &(ActivateMessage.ExecMessage));
  953.     Permit();
  954.     }
  955.  
  956. static void DisplayMessage(struct IntuiMessage *ActivateMessage)
  957.     {
  958.     fprintf(stderr, "ActivateMessage->ExecMessage.mn_Node.ln_Succ = %ld\n", ActivateMessage->ExecMessage.mn_Node.ln_Succ);
  959.     fprintf(stderr, "ActivateMessage->ExecMessage.mn_Node.ln_Pred = %ld\n", ActivateMessage->ExecMessage.mn_Node.ln_Pred);
  960.     fprintf(stderr, "ActivateMessage->ExecMessage.mn_Node.ln_Type = %d\n",  ActivateMessage->ExecMessage.mn_Node.ln_Type);
  961.     fprintf(stderr, "ActivateMessage->ExecMessage.mn_Node.ln_Pri  = %d\n",  ActivateMessage->ExecMessage.mn_Node.ln_Pri);
  962.     fprintf(stderr, "ActivateMessage->ExecMessage.mn_Node.ln_Name = %s\n",  ActivateMessage->ExecMessage.mn_Node.ln_Name);
  963.     fprintf(stderr, "ActivateMessage->ExecMessage.mn_ReplyPort    = %ld\n", ActivateMessage->ExecMessage.mn_ReplyPort);
  964.     fprintf(stderr, "ActivateMessage->ExecMessage.mn_Length       = %ld\n", ActivateMessage->ExecMessage.mn_Length);
  965.     fprintf(stderr, "ActivateMessage->Class                       = %ld\n", ActivateMessage->Class);
  966.     fprintf(stderr, "ActivateMessage->Code                        = %d\n",  ActivateMessage->Code);
  967.     fprintf(stderr, "ActivateMessage->Qualifier                   = %d\n",  ActivateMessage->Qualifier);
  968.     fprintf(stderr, "ActivateMessage->IAddress                    = %ld\n", ActivateMessage->IAddress);
  969.     fprintf(stderr, "ActivateMessage->MouseX                      = %d\n",  ActivateMessage->MouseX);
  970.     fprintf(stderr, "ActivateMessage->MouseY                      = %d\n",  ActivateMessage->MouseY);
  971.     fprintf(stderr, "ActivateMessage->Seconds                     = %ld\n", ActivateMessage->Seconds);
  972.     fprintf(stderr, "ActivateMessage->Micros                      = %ld\n", ActivateMessage->Micros);
  973.     fprintf(stderr, "ActivateMessage->IDCMPWindow                 = %ld\n", ActivateMessage->IDCMPWindow);
  974.     fprintf(stderr, "ActivateMessage->SpecialLink                 = %ld\n", ActivateMessage->SpecialLink);
  975. //    fprintf(stderr, "sizeof(struct IntuiMessage)                  = %ld\n", sizeof(struct IntuiMessage));
  976. //    fprintf(stderr, "sizeof(ActivateMessage->ExecMessage)         = %ld\n", sizeof(ActivateMessage->ExecMessage));
  977. //    fprintf(stderr, "sizeof(ActivateMessage->ExecMessage.mn_Node) = %ld\n", sizeof(ActivateMessage->ExecMessage.mn_Node));
  978.     }
  979. #endif
  980.  
  981. short FOXLIB LibVersion(void)
  982.     {
  983.     return Gui.LibVersion;
  984.     }
  985.  
  986. void GetWorkbenchSettings(void)
  987.     {
  988.     struct Screen *PubScreen;
  989.     Gui.WBPen[0] = (unsigned short) ~0;
  990.     if (Gui.LibVersion >= A500PLUS)
  991.         {
  992.         PubScreen = LockPubScreen("Workbench");
  993.         if (PubScreen)
  994.             {
  995.             struct DrawInfo *wbinfo = GetScreenDrawInfo(PubScreen);
  996.             if (wbinfo)
  997.                 {
  998.                 int l;
  999.                 Gui.WBMode = GetVPModeID(&(PubScreen->ViewPort));
  1000.                 Gui.WBDepth = wbinfo->dri_Depth;
  1001.                 for (l = 0; l <= NUM_WB_PENS - 1; l++)
  1002.                     Gui.WBPen[l] = wbinfo->dri_Pens[l];
  1003.                 Gui.WBPen[NUM_WB_PENS] = (unsigned short) ~0;
  1004.                 FreeScreenDrawInfo(PubScreen, wbinfo);
  1005.                 }
  1006.             UnlockPubScreen("Workbench", PubScreen);
  1007.             }
  1008.         else
  1009.             return;
  1010.         }
  1011.     }
  1012.  
  1013. #ifdef DIAGNOSTICS
  1014. void GuiReportError(char *error, short type)
  1015.    {
  1016.    if (Gui.DebugFile)
  1017.       fprintf(Gui.DebugFile, error);
  1018.    if (type == GUI_ERROR)
  1019.       fprintf(stderr, error);
  1020. #ifdef DEBUG
  1021.     // DEBUG is automatically defined by lc if -d1, -d2, -d3 or -d4 is
  1022.     // passed to lc.
  1023.     kprintf(error);
  1024. #endif
  1025.    }
  1026. #endif
  1027.  
  1028. unsigned short GuiDragPointer[] =
  1029.     {
  1030.     0x0000, 0x0000,
  1031.  
  1032.     0x0100, 0x0000,
  1033.     0x0380, 0x0000,
  1034.     0x07c0, 0x0000,
  1035.     0x0100, 0x0000,
  1036.     0x0100, 0x0000,
  1037.     0x2108, 0x0000,
  1038.     0x610c, 0x0000,
  1039.     0xfffe, 0x0000,
  1040.     0x610c, 0x0000,
  1041.     0x2108, 0x0000,
  1042.     0x0100, 0x0000,
  1043.     0x0100, 0x0000,
  1044.     0x07c0, 0x0000,
  1045.     0x0380, 0x0000,
  1046.     0x0100, 0x0000,
  1047.     0x0000, 0x0000,
  1048.  
  1049.     0xffff, 0xffff
  1050.     };
  1051.  
  1052. unsigned short waitPointer[] =
  1053.     {
  1054.     0x0000, 0x0000,
  1055.  
  1056.     0x0400, 0x07C0,
  1057.     0x0000, 0x07C0,
  1058.     0x0100, 0x0380,
  1059.     0x0000, 0x07E0,
  1060.     0x07C0, 0x1FF8,
  1061.     0x1FF0, 0x3FEC,
  1062.     0x3FF8, 0x7FDE,
  1063.     0x3FF8, 0x7FBE,
  1064.     0x7FFC, 0xFF7F,
  1065.     0x7EFC, 0xFFFF,
  1066.     0x7FFC, 0xFFFF,
  1067.     0x3FF8, 0x7FFE,
  1068.     0x3FF8, 0x7FFE,
  1069.     0x1FF0, 0x3FFC,
  1070.     0x07C0, 0x1FF8,
  1071.     0x0000, 0x07E0,
  1072.  
  1073.     0x0000, 0x0000,
  1074.     };
  1075.  
  1076. BOOL FOXLIB SleepPointer(REGA0 GuiWindow *win)
  1077.     {
  1078.     Diagnostic("SleepPointer", ENTER, TRUE);
  1079.     if (!win->Sleep)
  1080.         {
  1081.         InitRequester(&(win->Request));
  1082.         /* Putting a NULL requester in the window on an A500 (v34) succeeds but
  1083.             returns FALSE anyway!  So, if its an A500, assume success.  This may be
  1084.             a little dangerous but what do you expect from a bugged OS? */
  1085.         if (Request(&(win->Request), win->Win) || Gui.LibVersion < A3000)
  1086.             win->Sleep = TRUE;
  1087.         }
  1088.     if (win->Sleep && ChipMemForPointer)
  1089.         SetPointer(win->Win, ChipMemForPointer, 16, 16, -6, 0);
  1090.     Diagnostic("SleepPointer", EXIT, win->Sleep);
  1091.     return win->Sleep;
  1092.     }
  1093.  
  1094. void FOXLIB WakePointer(REGA0 GuiWindow *win)
  1095.     {
  1096.     int retval = win->Sleep;
  1097.  
  1098.     Diagnostic("WakePointer", ENTER, TRUE);
  1099.     if (win->Sleep)
  1100.         {
  1101.         EndRequest(&(win->Request), win->Win);
  1102.         if (ChipMemForPointer)
  1103.             ClearPointer(win->Win);
  1104.         win->Sleep = FALSE;
  1105.         }
  1106.     Diagnostic("WakePointer", EXIT, retval);
  1107.     }
  1108.  
  1109. void FOXLIB UseSafeMallocs(void)
  1110. {
  1111.     FastMallocs = FALSE;
  1112. }
  1113.  
  1114. // Priority 5001 - just after initialisation of auto variables.
  1115. int _STI_5001_InitGui(void)
  1116.    {
  1117.    Diagnostic("InitGui", ENTER, TRUE);
  1118.    Gui.DebugFile = NULL; // no-longer supported
  1119.     Gui.Proc = (struct Process *) FindTask(NULL);
  1120.    Gui.NumAllocs = 0;
  1121.    Gui.CleanupFlag = Gui.DroppingList = Gui.ListFocusOnly = FALSE;
  1122.    Gui.GGLfirst = NULL;
  1123.    Gui.GWLfirst = NULL;
  1124.    Gui.FirstEditBox = NULL;
  1125.     Gui.FirstListBox = NULL;
  1126.    Gui.FirstOutputBox = NULL;
  1127.     Gui.FirstTickBox = NULL;
  1128.     Gui.FirstRadioButton = NULL;
  1129.     Gui.FirstFrame = NULL;
  1130.     Gui.FirstTimer = NULL;
  1131.     Gui.FirstProgressBar = NULL;
  1132.     Gui.FirstTabControl = NULL;
  1133.     Gui.FirstUserGadget = NULL;
  1134.    memset(&(Gui.Message1), 0, sizeof(struct IntuiText));
  1135.    memset(&(Gui.Message2), 0, sizeof(struct IntuiText));
  1136.    memset(&(Gui.Message3), 0, sizeof(struct IntuiText));
  1137.    Gui.Message1.TopEdge =  0;
  1138.    Gui.Message2.TopEdge = 12;
  1139.    Gui.Message3.TopEdge = 24;
  1140.    Gui.Message1.ITextFont = Gui.Message2.ITextFont = Gui.Message3.ITextFont = &GuiFont;
  1141.    Gui.MessageNWin.IDCMPFlags  = 0;
  1142.    Gui.MessageNWin.FirstGadget = NULL;
  1143.    Gui.MessageNWin.CheckMark   = NULL;
  1144.    Gui.MessageNWin.BitMap      = NULL;
  1145.    Gui.MessageNWin.Title       = NULL;
  1146.    Gui.MessageNWin.Type        = CUSTOMSCREEN;
  1147.    Gui.MessageNWin.Flags       = SMART_REFRESH | NOCAREREFRESH;
  1148.    Gui.MessageDisplayed = FALSE;
  1149.    Gui.consig = Gui.winsig = Gui.scrsig = 0;
  1150.     Gui.HiPen = 1;
  1151.     Gui.LoPen = 2;
  1152.     Gui.BorderCol = Gui.TextCol = 1;
  1153.     Gui.BackCol = 0;
  1154.     FastMallocs = TRUE;
  1155.     GuiFont.ta_Name = GuiMalloc(11 * sizeof(char), 0);
  1156.     if (GuiFont.ta_Name)
  1157.         strcpy(GuiFont.ta_Name, "topaz.font");
  1158.     GuiFont.ta_YSize = 8;
  1159.     GuiFont.ta_Style = 0;
  1160.     GuiFont.ta_Flags = NULL;
  1161.     GuiULFont.ta_Name = GuiFont.ta_Name;
  1162.     GuiULFont.ta_YSize = 8;
  1163.     GuiULFont.ta_Style = 0;
  1164.     GuiULFont.ta_Flags = NULL;
  1165.  
  1166.     IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 33);
  1167.     if (!IntuitionBase)
  1168.         {
  1169.         SetLastErr("FoxGUI requires Intuition version 33 or above.");
  1170.         Diagnostic("InitGui", EXIT, FALSE);
  1171.         return 1;
  1172.         }
  1173.     Gui.LibVersion = ((struct Library *) IntuitionBase)->lib_Version;
  1174.     SetPeriod(24);
  1175.     SetDelay(240);
  1176.  
  1177.     // Open the console device just to do keymapping. (unit -1 means any unit)
  1178.     if (0 == OpenDevice("console.device", -1, (struct IORequest *) &ioreq, 0))
  1179.         {
  1180.         ConsoleDevice = (struct Library *)ioreq.io_Device;
  1181.         if (!(RKCbuffer = (unsigned char*) calloc(1, RKCbufferSize)))
  1182.             {
  1183.             CloseDevice((struct IORequest *) &ioreq);
  1184.             ConsoleDevice = NULL;
  1185.             }
  1186.         if (!(RKCevent = (struct InputEvent*) calloc(1, sizeof(struct InputEvent))))
  1187.             {
  1188.             free(RKCbuffer);
  1189.             CloseDevice((struct IORequest *) &ioreq);
  1190.             ConsoleDevice = NULL;
  1191.             }
  1192.         }
  1193.     if (!ConsoleDevice)
  1194.         SetLastErr("Failed to open console for raw key conversions");
  1195.  
  1196.    GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", Gui.LibVersion);
  1197.    if (!GfxBase)
  1198.         {
  1199.         Diagnostic("InitGui", EXIT, FALSE);
  1200.         return 1;
  1201.         }
  1202.     if (!(LayersBase = OpenLibrary("layers.library", 0L)))
  1203.         {
  1204.         Diagnostic("InitGui", EXIT, FALSE);
  1205.         return 1;
  1206.         }
  1207.  
  1208.     IFFParseBase = /*(struct IFFParseBase *)*/ OpenLibrary("iffparse.library", 0L);
  1209.  
  1210.     if (!(ChipMemForPointer = (unsigned short *) AllocMem(sizeof(waitPointer), MEMF_CHIP)))
  1211.         {
  1212.         Diagnostic("InitGui", EXIT, FALSE);
  1213.         return 1;
  1214.         }
  1215.     else
  1216.         memcpy(ChipMemForPointer, waitPointer, sizeof(waitPointer));
  1217.  
  1218.     if (!(ChipMemForDragPointer = (unsigned short *) AllocMem(sizeof(GuiDragPointer), MEMF_CHIP)))
  1219.         {
  1220.         Diagnostic("InitGui", EXIT, FALSE);
  1221.         return 1;
  1222.         }
  1223.     else
  1224.         memcpy(ChipMemForDragPointer, GuiDragPointer, sizeof(GuiDragPointer));
  1225.  
  1226.     GetWorkbenchSettings();
  1227.  
  1228.     Diagnostic("InitGui", EXIT, TRUE);
  1229.     return 0;
  1230.    }
  1231.  
  1232. BOOL FOXLIB SetGuiPensFromPubScreen(REGA0 char *pub_screen_name)
  1233. {
  1234.     BOOL retval = FALSE;
  1235.     struct Screen *pub_screen = NULL;
  1236.     struct DrawInfo *screen_drawinfo = NULL;
  1237.  
  1238.     if (pub_screen_name)
  1239.         pub_screen = LockPubScreen(pub_screen_name);
  1240.  
  1241.     if (pub_screen != NULL)
  1242.     {
  1243.         // Get the DrawInfo structure from the locked screen.  This returns pen, depth and font info.
  1244.         screen_drawinfo = GetScreenDrawInfo(pub_screen);
  1245.         if (screen_drawinfo != NULL)
  1246.         {
  1247.             SetGuiPens(screen_drawinfo->dri_Pens[SHINEPEN], screen_drawinfo->dri_Pens[SHADOWPEN]);
  1248.             retval = TRUE;
  1249.             FreeScreenDrawInfo(pub_screen, screen_drawinfo);
  1250.         }
  1251.         UnlockPubScreen(pub_screen_name, pub_screen);
  1252.     }
  1253.  
  1254.     return retval;
  1255. }
  1256.  
  1257. void FOXLIB SetGuiPens(REGD0 short hipen, REGD1 short lopen)
  1258.     {
  1259.     Gui.HiPen = hipen;
  1260.     Gui.LoPen = lopen;
  1261.     }
  1262.  
  1263. /*    Documentation for this function and DestroyMessage() have been excluded from FoxGui.guide
  1264.     because the functions themselves are in such poor shape.  They need completely re-thinking. */
  1265.  
  1266. BOOL FOXLIB ShowMessage(REGA0 GuiScreen *scr, REGA1 char *a, REGA2 char *b, REGA3 char *c, REGD0 int col)
  1267.    {
  1268.     int lena = a ? strlen(a) : 0, lenb = b ? strlen(b) : 0, lenc = c ? strlen(c) : 0;
  1269.  
  1270.    Diagnostic("ShowMessage", ENTER, TRUE);
  1271.    if (Gui.MessageDisplayed)
  1272.       return Diagnostic("ShowMessage", EXIT, FALSE);
  1273.    Gui.MessageDisplayed = TRUE;
  1274.    Gui.Message1.FrontPen = Gui.Message2.FrontPen = Gui.Message3.FrontPen = col;
  1275.    Gui.Message1.IText = a;
  1276.    Gui.Message2.IText = b;
  1277.    Gui.Message3.IText = c;
  1278.    if (b)
  1279.       Gui.Message1.NextText = &(Gui.Message2);
  1280.    if (c)
  1281.       Gui.Message2.NextText = &(Gui.Message3);
  1282.    Gui.MessageNWin.Width    = 8 * (max(lena, max(lenb, lenc)) + 6);
  1283.    Gui.MessageNWin.Height   = (12 * (1 + ((a) ? 1 : 0) + ((b) ? 1 : 0) + ((c) ? 1 : 0)));
  1284.    Gui.MessageNWin.LeftEdge = (640 - Gui.MessageNWin.Width) / 2;
  1285.    Gui.MessageNWin.TopEdge  = (256 - Gui.MessageNWin.Height) / 2;
  1286.    Gui.MessageNWin.BlockPen = Gui.MessageNWin.DetailPen = col;
  1287.    Gui.MessageNWin.Screen   = scr->scr;
  1288.    Gui.Message1.LeftEdge = (Gui.MessageNWin.Width - (lena * 8)) /2;
  1289.    Gui.Message2.LeftEdge = (Gui.MessageNWin.Width - (lenb * 8)) /2;
  1290.    Gui.Message3.LeftEdge = (Gui.MessageNWin.Width - (lenc * 8)) /2;
  1291.    Gui.MessageWin = (struct Window *) OpenWindow(&(Gui.MessageNWin));
  1292.    if (!(Gui.MessageWin))
  1293.       {
  1294.       Gui.Message1.IText = Gui.Message2.IText = Gui.Message3.IText = NULL;
  1295.       Gui.Message1.NextText = Gui.Message2.NextText = NULL;
  1296.       Gui.MessageDisplayed = FALSE;
  1297.       return Diagnostic("ShowMessage", EXIT, FALSE);
  1298.       }
  1299.    PrintIText(Gui.MessageWin->RPort, &(Gui.Message1), 0, 8);
  1300.    return Diagnostic("ShowMessage", EXIT, TRUE);
  1301.    }
  1302.  
  1303. BOOL FOXLIB DestroyMessage(void)
  1304.    {
  1305.    Diagnostic("DestroyMessage", ENTER, TRUE);
  1306.    if (!Gui.MessageDisplayed)
  1307.       return Diagnostic("DestroyMessage", EXIT, FALSE);
  1308.    CloseWindow(Gui.MessageWin);
  1309.    Gui.MessageDisplayed = FALSE;
  1310.    Gui.Message1.IText = Gui.Message2.IText = Gui.Message3.IText = NULL;
  1311.    Gui.Message1.NextText = Gui.Message2.NextText = NULL;
  1312.    return Diagnostic("DestroyMessage", EXIT, TRUE);
  1313.    }
  1314.  
  1315. void FOXLIB SetPeriod(REGD0 int time)
  1316.    {
  1317.    Diagnostic("SetPeriod", ENTER, TRUE);
  1318.    Gui.ARperiod = time;
  1319.    Diagnostic("SetPeriod", EXIT, TRUE);
  1320.    }
  1321.  
  1322. void FOXLIB SetDelay(REGD0 int time)
  1323.    {
  1324.    Diagnostic("SetDelay", ENTER, TRUE);
  1325.    Gui.ARdelay = time;
  1326.    Diagnostic("SetDelay", EXIT, TRUE);
  1327.    }
  1328.  
  1329. static void RefreshProgressBar(ProgressBar *pb)
  1330.     {
  1331.     if (pb && pb->hidden == 0)
  1332.         {
  1333.         int width, height, BevelHeight = pb->BevelPoints[7], BevelWidth = pb->BevelPoints[0] - 2,
  1334.                 backcol = GetBackCol(pb->WidgetData->Parent);
  1335.  
  1336.         if (pb->WidgetData->flags & PB_FILL_BT)
  1337.             {
  1338.             height = pb->iprogress * BevelHeight / pb->max;
  1339.             width = BevelWidth;
  1340.             AreaColFill(pb->win->Win->RPort, pb->light.LeftEdge + 2, pb->light.TopEdge + 1, width,
  1341.                     BevelHeight - height, backcol);
  1342.             }
  1343.         else
  1344.             {
  1345.             height = BevelHeight;
  1346.             width = pb->iprogress * BevelWidth / pb->max;
  1347.             AreaColFill(pb->win->Win->RPort, pb->light.LeftEdge + 2 + width, pb->light.TopEdge + 1,
  1348.                     BevelWidth - width, BevelHeight, backcol);
  1349.             }
  1350.         AreaColFill(pb->win->Win->RPort, pb->light.LeftEdge + 2, (pb->WidgetData->flags & PB_FILL_BT ?
  1351.                 BevelHeight - height : 0) + pb->light.TopEdge + 1, width, height, pb->fillcol);
  1352.         PrintIText(pb->win->Win->RPort, &pb->progress, 0, 0);
  1353.         DrawBorder(pb->win->Win->RPort, &pb->light, 0, 0);
  1354.         }
  1355.     }
  1356.  
  1357. static void setprogress(ProgressBar *pb, int progress, BOOL oldtext)
  1358.     {
  1359.     if (pb)
  1360.         {
  1361.         int penhold = pb->progress.FrontPen;
  1362.  
  1363.         // Blank out the previous text
  1364.         if (oldtext && pb->hidden == 0)
  1365.             {
  1366.             pb->progress.FrontPen = GetBackCol(pb->WidgetData->Parent);
  1367.             PrintIText(pb->win->Win->RPort, &(pb->progress), 0, 0);
  1368.             pb->progress.FrontPen = penhold;
  1369.             }
  1370.  
  1371.         pb->iprogress = min(progress, pb->max);
  1372.         pb->iprogress = max(pb->iprogress, 0);
  1373.  
  1374.         // Update the text
  1375.         if (pb->max == 100)
  1376.             sprintf(pb->progress.IText, "%-d%%", pb->iprogress);
  1377.         else
  1378.             sprintf(pb->progress.IText, "%-d", pb->iprogress);
  1379.         if ((pb->WidgetData->flags & PB_CAPTION_TOP_LEFT) || pb->WidgetData->flags & PB_CAPTION_BOTTOM_LEFT)
  1380.             {
  1381.             // Leave LeftEdge unchanged.  Unfortunately we need this IF statement here because the ELSE
  1382.             // part has to include TOP_RIGHT because that has a flag value of 0 so we can't check for it
  1383.             // directly!
  1384.             }
  1385.         else if (pb->WidgetData->flags & PB_CAPTION_CENTRE)
  1386.             pb->progress.LeftEdge = pb->light.LeftEdge - 1 +
  1387.                     ((pb->BevelPoints[12] + 1 - IntuiTextLength(&(pb->progress)))/2);
  1388.         else
  1389.             pb->progress.LeftEdge = pb->light.LeftEdge + pb->BevelPoints[12] - IntuiTextLength(&(pb->progress));
  1390.         RefreshProgressBar(pb);
  1391.         }
  1392.     }
  1393.  
  1394. void FOXLIB SetProgress(REGA0 ProgressBar *pb, REGD0 int progress)
  1395.     {
  1396.     setprogress(pb, progress, TRUE);
  1397.     }
  1398.  
  1399. void FOXLIB SetProgressMax(REGA0 ProgressBar *pb, REGD0 int progressmax)
  1400.     {
  1401.     if (pb && progressmax)
  1402.         {
  1403.         char *newtext, progtext[100]; // Excessive!
  1404.  
  1405.         sprintf(progtext, "%-d", progressmax);
  1406.         newtext = (char *) GuiMalloc((strlen(progtext) + 1) * sizeof(char), 0);
  1407.         if (newtext)
  1408.             {
  1409.             if (pb->hidden == 0)
  1410.                 {
  1411.                 int penhold = pb->progress.FrontPen;
  1412.                 pb->progress.FrontPen = pb->win->Win->RPort->BgPen;
  1413.                 PrintIText(pb->win->Win->RPort, &(pb->progress), 0, 0);
  1414.                 pb->progress.FrontPen = penhold;
  1415.                 }
  1416.             GuiFree(pb->progress.IText);
  1417.             pb->progress.IText = newtext;
  1418.             pb->max = progressmax;
  1419.             setprogress(pb, pb->iprogress, FALSE);
  1420.             }
  1421.         }
  1422.     }
  1423.  
  1424. static void UndrawProgressBar(ProgressBar *pb)
  1425.     {
  1426.     if (pb)
  1427.         {
  1428.         int penhold = pb->progress.FrontPen;
  1429.         BYTE BackCol = GetBackCol(pb->WidgetData->Parent);
  1430.  
  1431.         AreaColFill(pb->win->Win->RPort, pb->light.LeftEdge, pb->light.TopEdge, pb->BevelPoints[12]+1,
  1432.                 pb->BevelPoints[5]+1, BackCol);
  1433.         // Blank out the text
  1434.         pb->progress.FrontPen = BackCol;
  1435.         PrintIText(pb->win->Win->RPort, &(pb->progress), 0, 0);
  1436.         pb->progress.FrontPen = penhold;
  1437.         }
  1438.     }
  1439.  
  1440. BOOL ShowProgressBar(ProgressBar *pb)
  1441.     {
  1442.     if (pb)
  1443.         {
  1444.         if (pb->hidden == 1) // The progress bar is really hidden
  1445.             if ((!ISGUIWINDOW(pb->WidgetData->Parent)) && ((Frame *) pb->WidgetData->Parent)->hidden != 0)
  1446.                 pb->hidden = -1; // The progress bar is in a hidden frame so it will remain hidden
  1447.             else
  1448.                 pb->hidden = 0;
  1449.         if (pb->hidden == 0)
  1450.             RefreshProgressBar(pb);
  1451.         return TRUE;
  1452.         }
  1453.     return FALSE;
  1454.     }
  1455.  
  1456. BOOL HideProgressBar(ProgressBar *pb)
  1457.     {
  1458.     if (pb)
  1459.         {
  1460.         if (pb->hidden == 0)
  1461.             UndrawProgressBar(pb);
  1462.         pb->hidden = 1;
  1463.         return TRUE;
  1464.         }
  1465.     return FALSE;
  1466.     }
  1467.  
  1468. void DestroyProgressBar(ProgressBar *pb, BOOL refresh)
  1469.     {
  1470.     if (pb)
  1471.         {
  1472.         Frame *Child; // Could be any type of object
  1473.         if (refresh)
  1474.             HideProgressBar(pb);
  1475.  
  1476.         if (pb->progress.ITextFont)
  1477.             {
  1478.             if (pb->progress.ITextFont->ta_Name)
  1479.                 GuiFree(pb->progress.ITextFont->ta_Name);
  1480.             GuiFree(pb->progress.ITextFont);
  1481.             }
  1482.  
  1483.         GuiFree(pb->progress.IText);
  1484.         if (pb->WidgetData->os)
  1485.             GuiFree(pb->WidgetData->os);
  1486.         if (pb == Gui.FirstProgressBar)
  1487.             Gui.FirstProgressBar = pb->Next;
  1488.         else
  1489.             {
  1490.             ProgressBar *n = Gui.FirstProgressBar;
  1491.             while (n->Next && n->Next != pb)
  1492.                 n = n->Next;
  1493.             if (n->Next == pb)
  1494.                 n->Next = pb->Next;
  1495.             }
  1496.         Child = pb->WidgetData->ChildWidget;
  1497.         while (Child)
  1498.             {
  1499.             void *next = Child->WidgetData->NextWidget;
  1500.             Child->WidgetData->ParentControl = NULL; // Otherwise destroy will fail.
  1501.             Destroy(Child, refresh);
  1502.             Child = next;
  1503.             }
  1504.         GuiFree(pb->WidgetData);
  1505.         GuiFree(pb);
  1506.         }
  1507.     }
  1508.  
  1509. void ResizeProgressBar(ProgressBar *pb, int x, int y, int width, int height, BOOL eraseold)
  1510.     {
  1511.     unsigned short FontHeight = GetFontHeight(pb->win);
  1512.  
  1513.     if (eraseold && GetBackCol(pb->WidgetData->Parent) == pb->win->Win->RPort->BgPen)
  1514.         UndrawProgressBar(pb);
  1515.  
  1516.     MakeBevel(&(pb->light), &(pb->dark), pb->BevelPoints, x, y, width, height, pb->WidgetData->flags & PB_INSET ?
  1517.             FALSE : TRUE);
  1518.  
  1519.     if (pb->WidgetData->flags & PB_CAPTION_TOP_LEFT || pb->WidgetData->flags & PB_CAPTION_BOTTOM_LEFT)
  1520.         pb->progress.LeftEdge = x;
  1521.     /*    No need to set the LeftEdge if the caption is on the right or in the centre.  It will get done
  1522.         in SetProgress(). */
  1523.     if (pb->WidgetData->flags & PB_CAPTION_CENTRE)
  1524.         pb->progress.TopEdge = y + ((height - FontHeight)/2);
  1525.     else if (pb->WidgetData->flags & PB_CAPTION_BOTTOM_LEFT || pb->WidgetData->flags & PB_CAPTION_BOTTOM_RIGHT)
  1526.         pb->progress.TopEdge = y + height + 2;
  1527.     else
  1528.         pb->progress.TopEdge = y - FontHeight - 2;
  1529.     pb->WidgetData->left = x;
  1530.     pb->WidgetData->top = y;
  1531.     pb->WidgetData->width = width;
  1532.     pb->WidgetData->height = height;
  1533.     }
  1534.  
  1535. ProgressBar* FOXLIB MakeProgressBar(REGA0 void *Parent, REGD0 int left, REGD1 int top, REGD2 int width,
  1536.         REGD3 int height, REGD4 short fillcol, REGD5 short flags, REGA1 void *extension)
  1537.     {
  1538.     if (Parent && width && height)
  1539.         {
  1540.         ProgressBar *pb;
  1541.         GuiWindow *win;
  1542.         Frame *ParentFrame = NULL;
  1543.  
  1544.         if (!(pb = (ProgressBar *) GuiMalloc(sizeof(ProgressBar), 0)))
  1545.             return NULL;
  1546.         if (!(pb->WidgetData = (Widget *) GuiMalloc(sizeof(Widget), 0)))
  1547.         {
  1548.             GuiFree(pb);
  1549.             return NULL;
  1550.         }
  1551.         pb->WidgetData->ObjectType = ProgressBarObject;
  1552.         pb->WidgetData->Parent = Parent;
  1553.         pb->WidgetData->NextWidget = NULL;
  1554.         pb->WidgetData->ChildWidget = NULL;
  1555.         // Assume progress % - "100%" is longest text.
  1556.         if (!(pb->progress.IText = (char *) GuiMalloc(5 * sizeof(char), 0)))
  1557.             {
  1558.             GuiFree(pb->WidgetData);
  1559.             GuiFree(pb);
  1560.             return NULL;
  1561.             }
  1562.  
  1563.         if (!ISGUIWINDOW(Parent))
  1564.             {
  1565.             ParentFrame = (Frame *) Parent;
  1566.             left += ParentFrame->button.LeftEdge;
  1567.             top += ParentFrame->button.TopEdge;
  1568.             win = (GuiWindow *) ParentFrame->button.UserData;
  1569.             }
  1570.         else
  1571.             win = (GuiWindow *) Parent;
  1572.  
  1573.         if (ParentFrame && (flags & S_AUTO_SIZE) && !(ParentFrame->WidgetData->flags & S_AUTO_SIZE))
  1574.             flags ^= S_AUTO_SIZE;
  1575.         if (flags & S_AUTO_SIZE)
  1576.             {
  1577.             if (!(pb->WidgetData->os = (OriginalSize *) GuiMalloc(sizeof(OriginalSize), 0)))
  1578.                 {
  1579.                 GuiFree(pb->progress.IText);
  1580.                 GuiFree(pb->WidgetData);
  1581.                 GuiFree(pb);
  1582.                 return NULL;
  1583.                 }
  1584.             pb->WidgetData->os->left = left;
  1585.             pb->WidgetData->os->top = top;
  1586.             pb->WidgetData->os->width = width;
  1587.             pb->WidgetData->os->height = height;
  1588.             }
  1589.         else
  1590.             pb->WidgetData->os = NULL;
  1591.  
  1592.         pb->win = win;
  1593.         pb->WidgetData->flags = flags;
  1594.         pb->fillcol = fillcol;
  1595.         pb->max = 100;
  1596.         if (ParentFrame && ParentFrame->hidden != 0)
  1597.             pb->hidden = -1;
  1598.         else
  1599.             pb->hidden = 0;
  1600.  
  1601.         pb->progress.DrawMode = JAM1;
  1602.         pb->progress.FrontPen = Gui.TextCol;
  1603.         pb->progress.ITextFont = CopyFont(&GuiFont);
  1604.         pb->progress.NextText = NULL;
  1605.  
  1606.         ResizeProgressBar(pb, left, top, width, height, FALSE);
  1607.  
  1608.         pb->Next = Gui.FirstProgressBar;
  1609.         Gui.FirstProgressBar = pb;
  1610.         setprogress(pb, 0, FALSE);
  1611.         return pb;
  1612.         }
  1613.     return NULL;
  1614.     }
  1615.  
  1616. BOOL DestroyTimer(Timer *t)
  1617.     {
  1618.     if (t)
  1619.         {
  1620.         Frame *Child; // Could be any type of control
  1621.         Timer *n = Gui.FirstTimer, *np = NULL;
  1622.         while (n && n != t)
  1623.             {
  1624.             np = n;
  1625.             n = n->NextTimer;
  1626.             }
  1627.         if (!n)
  1628.             return FALSE;
  1629.         if (np)
  1630.             np->NextTimer = n->NextTimer;
  1631.         else
  1632.             Gui.FirstTimer = n->NextTimer;
  1633.         Child = n->WidgetData->ChildWidget;
  1634.         while (Child)
  1635.             {
  1636.             void *next = Child->WidgetData->NextWidget;
  1637.             Child->WidgetData->ParentControl = NULL; // Otherwise destroy will fail.
  1638.             Destroy(Child, TRUE);
  1639.             Child = next;
  1640.             }
  1641.         GuiFree(n->WidgetData);
  1642.         GuiFree(n);
  1643.         return TRUE;
  1644.         }
  1645.     return FALSE;
  1646.     }
  1647.  
  1648. void DestroyAllTimers(void)
  1649.     {
  1650.     while (Gui.FirstTimer)
  1651.         DestroyTimer(Gui.FirstTimer);
  1652.     }
  1653.  
  1654. Timer* FOXLIB MakeTimer(REGD0 short flags, REGA0 int (* __far __stdargs CallFn) (Timer *, long), REGA1 void *extension)
  1655.     {
  1656.     Timer *t = (Timer*) GuiMalloc(sizeof(Timer), 0);
  1657.  
  1658.     if (t)
  1659.         {
  1660.         if (!(t->WidgetData = (Widget *) GuiMalloc(sizeof(Widget), 0)))
  1661.             {
  1662.             GuiFree(t);
  1663.             return NULL;
  1664.             }
  1665.         t->WidgetData->ObjectType = TimerObject;
  1666.         t->WidgetData->flags = flags;
  1667.         t->WidgetData->left = 0;
  1668.         t->WidgetData->top = 0;
  1669.         t->WidgetData->width = 0;
  1670.         t->WidgetData->height = 0;
  1671.         t->WidgetData->NextWidget = NULL;
  1672.         t->WidgetData->ChildWidget = NULL;
  1673.         t->running = FALSE;
  1674.         t->Callfn = CallFn;
  1675.         t->NextTimer = Gui.FirstTimer;
  1676.         Gui.FirstTimer = t;
  1677.         }
  1678.     return t;
  1679.     }
  1680.  
  1681. void FOXLIB StartTimer(REGA0 Timer *t)
  1682.     {
  1683.     if (t)
  1684.         {
  1685.         t->lasttrigger = t->starttimesecs = t->timesecs = time(NULL);
  1686.         t->running = TRUE;
  1687.         t->paused = FALSE;
  1688.         }
  1689.     }
  1690.  
  1691. void FOXLIB StopTimer(REGA0 Timer *t)
  1692.     {
  1693.     if (t)
  1694.         {
  1695.         t->timesecs = time(NULL);
  1696.         t->running = FALSE;
  1697.         }
  1698.     }
  1699.  
  1700. void FOXLIB PauseTimer(REGA0 Timer *t)
  1701.     {
  1702.     if (t)
  1703.         if (!t->paused)
  1704.             {
  1705.             t->pausetimesecs = time(NULL);
  1706.             t->running = FALSE;
  1707.             t->paused = TRUE;
  1708.             }
  1709.     }
  1710.  
  1711. void FOXLIB UnpauseTimer(REGA0 Timer *t)
  1712.     {
  1713.     if (t)
  1714.         if (t->paused)
  1715.             {
  1716.             t->starttimesecs += time(NULL) - t->pausetimesecs;
  1717.             t->running = TRUE;
  1718.             t->paused = FALSE;
  1719.             }
  1720.     }
  1721.  
  1722. void FOXLIB AddTime(REGA0 Timer *t, REGD0 long secs)
  1723.     {
  1724.     if (t && secs)
  1725.         t->starttimesecs -= secs;
  1726.     }
  1727.  
  1728. void FOXLIB SetTime(REGA0 Timer *t, REGD0 long secs)
  1729.     {
  1730.     if (t && secs)
  1731.         {
  1732.         t->starttimesecs = time(NULL) - secs;
  1733.         if (t->paused)
  1734.             t->pausetimesecs = t->starttimesecs + secs;
  1735.         }
  1736.     }
  1737.  
  1738. static void WinPrintReverse(GuiWindow *win, char *text, int width)
  1739.     {
  1740.     int i;
  1741.     WinPrint(win, "\033[7m");
  1742.     WinPrint(win, text);
  1743.     for (i = strlen(text) + 1; i <= width; i++)
  1744.         WinPrint(win, " ");
  1745.     WinPrint(win, "\033[0m");
  1746.     }
  1747.  
  1748. static void WinPrintWidth(GuiWindow *win, char *text, int width)
  1749.     {
  1750.     int i;
  1751.     WinPrint(win, text);
  1752.     for (i = strlen(text) + 1; i <= width; i++)
  1753.         WinPrint(win, " ");
  1754.     }
  1755.  
  1756. void DrawRPLines(struct RastPort *rp, short *points, int count, int col, BYTE mode, int xoffset, int yoffset)
  1757.     {
  1758.    struct Border border;
  1759.    memset(&border, 0, sizeof(struct Border));
  1760.    border.FrontPen = col;
  1761.    border.DrawMode = mode;
  1762.    border.Count = count;
  1763.    border.XY = points;
  1764.    DrawBorder(rp, &border, xoffset, yoffset);
  1765.    }
  1766.  
  1767. void FOXLIB DrawLines(REGA0 GuiWindow *win, REGA1 short *points, REGD0 int count, REGD1 int col)
  1768.    {
  1769.     DrawRPLines(win->Win->RPort, points, count, col, JAM1, 0, 0);
  1770.     }
  1771.  
  1772. static BOOL CloseGuiScreen(GuiScreen *scr)
  1773.    {
  1774.     GuiScreen *ps = NULL, *s = Gui.FirstScr;
  1775.    short temp = Gui.CleanupFlag;
  1776.     BOOL success = TRUE;
  1777.    Diagnostic("CloseGuiScreen", ENTER, TRUE);
  1778.     if (!scr)
  1779.         return Diagnostic("CloseGuiScreen", EXIT, FALSE);
  1780.    Gui.CleanupFlag = TRUE;
  1781.     /*    Close any windows on the screen that are owned by this app.  If the screen is public then there
  1782.         may still be windows from other apps that we don't know about. */
  1783.    CloseScrWindows(scr);
  1784.    Gui.CleanupFlag = temp;
  1785.  
  1786.     /* Before V36, CloseScreen() had no return value but there was no such thing as a public screen and
  1787.         CloseScreen() never failed.  From V36 onwards, CloseScreen() returns a boolean and will fail if
  1788.         there are any windows open on the screen, whether owned by this app or any other! */
  1789.     if (Gui.LibVersion < 36)
  1790.        CloseScreen(scr->scr);
  1791.     else
  1792.         success = CloseScreen(scr->scr);
  1793.     if (success)
  1794.         {
  1795.         while (s && s != scr)
  1796.             {
  1797.             ps = s;
  1798.             s = s->NextScr;
  1799.             }
  1800.         if (s)
  1801.             {
  1802.             if (ps)
  1803.                 ps->NextScr = s->NextScr;
  1804.             else
  1805.                 Gui.FirstScr = s->NextScr;
  1806.             }
  1807.  
  1808.         if (scr->nsc->Font)
  1809.         {
  1810.             if (scr->nsc->Font->ta_Name)
  1811.                 GuiFree(scr->nsc->Font->ta_Name);
  1812.             GuiFree(scr->nsc->Font);
  1813.         }
  1814.  
  1815.        GuiFree(scr->nsc);
  1816.         if (scr->PubName)
  1817.             GuiFree(scr->PubName);
  1818.         if (scr->LastWinSig)
  1819.             FreeSignal(scr->LastWinSig);
  1820.         GuiFree(scr->Screen_Tags);
  1821.        GuiFree(scr->WidgetData);
  1822.        GuiFree(scr);
  1823.         }
  1824.    return Diagnostic("CloseGuiScreen", EXIT, success);
  1825.    }
  1826.  
  1827. static void CloseAllGuiScreens(void)
  1828.     {
  1829.     GuiScreen *ns, *s = Gui.FirstScr;
  1830.  
  1831.     while (s)
  1832.         {
  1833.         ns = s->NextScr;
  1834.         CloseGuiScreen(s);
  1835.         s = ns;
  1836.         }
  1837.     }
  1838.  
  1839. GuiScreen* FOXLIB OpenGuiScreen(REGD0 int Depth, REGD1 int DPen, REGD2 int BPen, REGA0 char *Title,
  1840.         REGA1 int (* __far __stdargs LastWinFn)(GuiScreen *), REGD3 int flags, REGA2 char *PubName, REGD4 unsigned long DisplayID,
  1841.         REGD5 int OverscanType, REGD6 UWORD *pens, REGA3 void *extension)
  1842.    {
  1843.    GuiScreen *gs;
  1844.    struct ExtNewScreen *ns;
  1845.     int NumTags, l;
  1846.     unsigned short *pa = NULL;
  1847.    Diagnostic("OpenGuiScreen", ENTER, TRUE);
  1848.  
  1849.    if (!(ns = (struct ExtNewScreen *) GuiMalloc(sizeof(struct ExtNewScreen), 0)))
  1850.       {
  1851.       Diagnostic("OpenGuiScreen", EXIT, FALSE);
  1852.       return NULL;
  1853.       }
  1854.    if (!(gs = (GuiScreen *) GuiMalloc(sizeof(GuiScreen), 0)))
  1855.       {
  1856.       GuiFree(ns);
  1857.       Diagnostic("OpenGuiScreen", EXIT, FALSE);
  1858.       return NULL;
  1859.       }
  1860.    if (!(gs->WidgetData = (Widget *) GuiMalloc(sizeof(Widget), 0)))
  1861.       {
  1862.       GuiFree(gs);
  1863.       GuiFree(ns);
  1864.       Diagnostic("OpenGuiScreen", EXIT, FALSE);
  1865.       return NULL;
  1866.       }
  1867.     gs->WidgetData->ObjectType = ScreenObject;
  1868.     gs->WidgetData->NextWidget = NULL;
  1869.     gs->WidgetData->ChildWidget = NULL;
  1870.     if (PubName)
  1871.         {
  1872.         if (strcmp(PubName, "") && Gui.LibVersion >= 36)
  1873.             {
  1874.             if (!(gs->PubName = (char *) GuiMalloc((strlen(PubName) + 1) * sizeof(char), 0)))
  1875.                 {
  1876.                 GuiFree(gs->WidgetData);
  1877.                 GuiFree(gs);
  1878.               GuiFree(ns);
  1879.               Diagnostic("OpenGuiScreen", EXIT, FALSE);
  1880.               return NULL;
  1881.                 }
  1882.             strcpy(gs->PubName, PubName);
  1883.             }
  1884.         else
  1885.             gs->PubName = NULL;
  1886.         }
  1887.     else
  1888.         gs->PubName = NULL;
  1889.    gs->nsc = ns;
  1890.     for (l = 0; l <= NUM_WB_PENS - 1; l++)
  1891.         gs->Pens[l] = Gui.WBPen[l];  /* For now... */
  1892.     gs->Pens[NUM_WB_PENS] = (unsigned short) ~0;
  1893.     ns->LeftEdge = 0;
  1894.    ns->TopEdge = 0;
  1895.     ns->Width = (Gui.LibVersion >= 36 ? STDSCREENWIDTH : GfxBase->NormalDisplayColumns);
  1896.     ns->Height = STDSCREENHEIGHT;
  1897.    ns->Depth = Depth;
  1898.    ns->DetailPen = DPen;
  1899.    ns->BlockPen = BPen;
  1900.     ns->ViewModes = HIRES;
  1901.    ns->Type = CUSTOMSCREEN | NS_EXTENDED;
  1902.     ns->Font = CopyFont(&GuiFont);
  1903.    ns->DefaultTitle = Title;
  1904.    ns->Gadgets = NULL;
  1905.    ns->CustomBitMap = NULL;
  1906.  
  1907.     //    Work out how many tags we need.  Start with 2 (one for pens, one for the TAG_DONE).
  1908.     NumTags = 2 + (gs->PubName ? 1 : 0) + (gs->PubName && LastWinFn ? 1 : 0) + (flags & GS_OVERSCAN ? 1 :
  1909.             0) + (flags & GS_AUTOSCROLL ? 1 : 0) + (flags & GS_DISPLAY_ID ? 1 : 0);
  1910.  
  1911.     if (!(gs->Screen_Tags = (struct TagItem*) GuiMalloc(NumTags * sizeof(struct TagItem), 0)))
  1912.         {
  1913.         if (gs->PubName)
  1914.             GuiFree(gs->PubName);
  1915.         GuiFree(gs->WidgetData);
  1916.         GuiFree(gs);
  1917.          GuiFree(ns);
  1918.         Diagnostic("OpenGuiScreen", EXIT, FALSE);
  1919.          return NULL;
  1920.         }
  1921.  
  1922.     ns->Extension = gs->Screen_Tags;
  1923.     gs->Screen_Tags[0].ti_Tag = SA_Pens;
  1924.     gs->Screen_Tags[0].ti_Data = (unsigned long) gs->Pens;
  1925.     gs->LastWinFn = LastWinFn;
  1926.     gs->LastWinSig = 0;
  1927.     if (gs->PubName)
  1928.         {
  1929.         /*    Open the screen as a public screen.  Even public screens start off private so we will still
  1930.             have to send it public after it has opened. */
  1931.         gs->Screen_Tags[1].ti_Tag = SA_PubName;
  1932.         gs->Screen_Tags[1].ti_Data = (unsigned long) gs->PubName;
  1933.         l = 2;
  1934.         if (LastWinFn)
  1935.             {
  1936.             /*    Set up the screen so that this task will be signalled when the last window closes on this
  1937.                 public screen. */
  1938.             BYTE signal = AllocSignal(-1);
  1939.             if (signal == -1)
  1940.                 {
  1941.                 GuiFree(gs->PubName);
  1942.                 GuiFree(gs->WidgetData);
  1943.                 GuiFree(gs);
  1944.               GuiFree(ns);
  1945.               Diagnostic("OpenGuiScreen", EXIT, FALSE);
  1946.               return NULL;
  1947.                 }
  1948.             gs->LastWinSig = signal;
  1949.             gs->Screen_Tags[2].ti_Tag = SA_PubSig;
  1950.             gs->Screen_Tags[2].ti_Data = (unsigned long) signal;
  1951.             l = 3;
  1952.             }
  1953.         }
  1954.     else
  1955.         l = 1;
  1956.     if (flags & GS_AUTOSCROLL)
  1957.         {
  1958.         gs->Screen_Tags[l].ti_Tag = SA_AutoScroll;
  1959.         gs->Screen_Tags[l++].ti_Data = TRUE;
  1960.         }
  1961.     if (flags & GS_DISPLAY_ID)
  1962.         {
  1963.         gs->Screen_Tags[l].ti_Tag = SA_DisplayID;
  1964.         gs->Screen_Tags[l].ti_Data = DisplayID;
  1965.         ns->ViewModes = gs->Screen_Tags[l++].ti_Data;
  1966.         }
  1967.     if (flags & GS_INTERLACE)
  1968.         ns->ViewModes |= INTERLACE;
  1969.     if (flags & GS_OVERSCAN)
  1970.         {
  1971.         gs->Screen_Tags[l].ti_Tag = SA_Overscan;
  1972.         gs->Screen_Tags[l++].ti_Data = OverscanType;
  1973.         }
  1974.     if (flags & GS_PENS)
  1975.     {
  1976.         gs->Screen_Tags[0].ti_Data = (unsigned long) pens;
  1977.         pa = (unsigned short *) gs->Screen_Tags[0].ti_Data;
  1978.     }
  1979.     gs->Screen_Tags[l].ti_Tag = TAG_DONE;
  1980.     /* Open the screen using the 3D look but in a backwards compatible way
  1981.         rather than using OpenScreenTags() or OpenScreenTagList() which are
  1982.         simpler but not backwards compatible */
  1983.     gs->scr = (struct Screen *) OpenScreen((struct NewScreen *) ns);
  1984.    if (!(gs->scr))
  1985.       {
  1986.         if (gs->PubName)
  1987.             GuiFree(gs->PubName);
  1988.       GuiFree(ns);
  1989.       GuiFree(gs->WidgetData);
  1990.       GuiFree(gs);
  1991.       Diagnostic("OpenGuiScreen", EXIT, FALSE);
  1992.       return NULL;
  1993.       }
  1994.  
  1995.     gs->NextScr = Gui.FirstScr;
  1996.     Gui.FirstScr = gs;
  1997.  
  1998.     if (gs->PubName) // Send the screen public!
  1999.         PubScreenStatus(gs->scr, 0);
  2000.  
  2001.    Diagnostic("OpenGuiScreen", EXIT, TRUE);
  2002.    return gs;
  2003.    }
  2004.  
  2005. struct Screen* FOXLIB GetScreenDetails(REGA0 void *scr, REGA1 unsigned long *mode, REGA2 int *depth, REGA3 char *fontname, REGD0 int bufsize,
  2006.         REGD1 int *reqbufsize, REGD2 int *fontheight, REGD3 int *fontstyle, REGD4 UWORD *pens, REGD5 int pensarraysize)
  2007. {
  2008.     struct Screen *screen = NULL;
  2009.  
  2010.     if (ISGUISCREEN(scr))
  2011.         screen = ((GuiScreen *) scr)->scr;
  2012.     else
  2013.         screen = LockPubScreen((UBYTE *) scr);
  2014.  
  2015.     if (screen != NULL)
  2016.     {
  2017.         // Get the DrawInfo structure from the screen.  This returns pen, depth and font info.
  2018.         struct DrawInfo *screen_drawinfo = GetScreenDrawInfo(screen);
  2019.  
  2020.         if (screen_drawinfo != NULL)
  2021.         {
  2022.             int reqsize;
  2023.  
  2024.             reqsize = strlen(screen_drawinfo->dri_Font->tf_Message.mn_Node.ln_Name) + 1;
  2025.             if (reqbufsize)
  2026.                 *reqbufsize = reqsize;
  2027.             if (fontname && bufsize >= reqsize)
  2028.                 strcpy(fontname, screen_drawinfo->dri_Font->tf_Message.mn_Node.ln_Name);
  2029.             else if (fontname)
  2030.             {
  2031.                 strncpy(fontname, screen_drawinfo->dri_Font->tf_Message.mn_Node.ln_Name, bufsize - 1);
  2032.                 fontname[bufsize - 1] = 0;
  2033.             }
  2034.             if (fontheight)
  2035.                 *fontheight = screen_drawinfo->dri_Font->tf_YSize;
  2036.             if (fontstyle)
  2037.                 *fontstyle = screen_drawinfo->dri_Font->tf_Style;
  2038.  
  2039.             if (depth)
  2040.                 *depth = screen_drawinfo->dri_Depth;
  2041.  
  2042.             if (pens)
  2043.             {
  2044.                 int i;
  2045.  
  2046.                 for (i = 0; i < NUMDRIPENS && pensarraysize > i; i++)
  2047.                     pens[i] = screen_drawinfo->dri_Pens[i];
  2048.             }
  2049.  
  2050.             FreeScreenDrawInfo(screen, screen_drawinfo);
  2051.         }
  2052.  
  2053.         if (mode)
  2054.             *mode = GetVPModeID(&(screen->ViewPort));
  2055.  
  2056.         if (!(ISGUISCREEN(scr)))
  2057.             UnlockPubScreen((UBYTE *) scr, screen);
  2058.     }
  2059.     return screen;
  2060. }
  2061.  
  2062. GuiScreen* FOXLIB ClonePublicScreen(REGD0 int mindepth, REGA3 UBYTE *pub_screen_name, REGA0 char *sScreenTitle,
  2063.         REGA1 int (* __far __stdargs LastWinFn)(GuiScreen *), REGD1 int flags, REGA2 char *new_pub_name, REGD5 int OverscanType,
  2064.         REGD2 void *extension)
  2065. {
  2066.     unsigned long mode;
  2067.     int depth, reqfontnamesize, fontheight, fontstyle;
  2068.     char fontname[100];
  2069.     UWORD pens[NUMDRIPENS];
  2070.  
  2071.     GetScreenDetails(pub_screen_name, &mode, &depth, fontname, 100, &reqfontnamesize, &fontheight, &fontstyle, pens, NUMDRIPENS);
  2072.  
  2073.     if (flags & GS_CLONEFONT)
  2074.         SetDefaultFont(fontname, fontheight, fontstyle);
  2075.  
  2076.     if (flags & GS_CLONEPENS)
  2077.         SetGuiPens(pens[SHINEPEN], pens[SHADOWPEN]);
  2078.  
  2079.     return OpenGuiScreen(max(depth, mindepth), pens[DETAILPEN], pens[BLOCKPEN], sScreenTitle, LastWinFn, GS_AUTOSCROLL | GS_DISPLAY_ID |
  2080.             (OverscanType ? GS_OVERSCAN : 0) | GS_PENS, new_pub_name, mode, OverscanType, pens, NULL);
  2081. }
  2082.  
  2083. void QueueAllMessages(void)
  2084.    {
  2085.    GuiWindow *gwl = Gui.GWLfirst;
  2086.     GuiScreen *gs = Gui.FirstScr;
  2087.    Gui.consig = Gui.winsig = Gui.scrsig = 0;
  2088.    while (gwl)
  2089.       {
  2090.         if (gwl->ConReadSig != 0)
  2091.           QRead(gwl, &(Gui.ibuf));
  2092.       Gui.winsig |= gwl->WindowSig;
  2093.       Gui.consig |= gwl->ConReadSig;
  2094.       gwl = gwl->next;
  2095.       }
  2096.     while (gs)
  2097.         {
  2098.         Gui.scrsig |= (1L << gs->LastWinSig);
  2099.         gs = gs->NextScr;
  2100.         }
  2101.    }
  2102.  
  2103. void AbortAllMessages(void)
  2104.    {
  2105.    GuiWindow *gwl = Gui.GWLfirst;
  2106.    while (gwl)
  2107.       {
  2108.         if (gwl->ConReadSig != 0)
  2109.             {
  2110.           if (!(CheckIO((struct IORequest*) gwl->Con->ConIn)))
  2111.              AbortIO((struct IORequest*) gwl->Con->ConIn);
  2112.           WaitIO((struct IORequest*) gwl->Con->ConIn);
  2113.             }
  2114.       gwl = gwl->next;
  2115.       }
  2116.    }
  2117.  
  2118. // Pauses for the specified number of milliseconds or until the button is released.
  2119. static struct IntuiMessage *pause(int time, GuiWindow *winptr)
  2120.    {
  2121.    struct IntuiMessage *ReleaseMessage = NULL;
  2122.    unsigned int clock[2], startclock[2];
  2123.     register unsigned long elapsed;
  2124.  
  2125.     timer(startclock); // Get the seconds and micro seconds of the system clock into the startclock array.
  2126.     do
  2127.       {
  2128.       ReleaseMessage = (struct IntuiMessage *) GetMsg(winptr->Win->UserPort);
  2129.       if (ReleaseMessage)
  2130.          {
  2131.          if (!(ReleaseMessage->Class == GADGETUP || (ReleaseMessage->Class == MOUSEBUTTONS && ReleaseMessage->Code ==
  2132.             SELECTUP)))
  2133.             {
  2134.             ReplyMsg((struct Message *) ReleaseMessage);
  2135.             ReleaseMessage = NULL;
  2136.             }
  2137.          }
  2138.         timer(clock);
  2139.         // Work out how much time has passed since the start of the loop
  2140.         elapsed = ((clock[0] - startclock[0]) * 1000000) + (clock[1] - startclock[1]);
  2141.         elapsed /= 1000;
  2142.       } while (elapsed < time && !ReleaseMessage);
  2143.    return ReleaseMessage;
  2144.    }
  2145.  
  2146. static PushButton *FindButtonByMsg(struct IntuiMessage *WinMsg)
  2147.    {
  2148.    PushButton *ggl = Gui.GGLfirst, *RetVal = NULL;
  2149.    while (ggl)
  2150.       {
  2151.       if (&(ggl->button) == (struct Gadget *) WinMsg->IAddress)
  2152.          {
  2153.          RetVal = ggl;
  2154.          break;
  2155.          }
  2156.       ggl = ggl->Next;
  2157.       }
  2158.    return RetVal;
  2159.    }
  2160.  
  2161. static Frame *CheckForChildren(Frame *f, int x, int y)
  2162.     {
  2163.     /* This function checks to see whether any children of the specified frame are also at this
  2164.         position.  If so, the child frame is selected instead. */
  2165.  
  2166.     Frame *c = Gui.FirstFrame;
  2167.  
  2168.     while (c)
  2169.         {
  2170.         BOOL rounded = ((c->WidgetData->flags & SYS_FM_ROUNDED) && c->points[1] + 1 >= 6 && !(c->WidgetData->flags & FM_BORDERLESS));
  2171.         if (c->WidgetData->Parent == f && x >= c->button.LeftEdge && x <= c->button.LeftEdge + (rounded ? c->points[24]
  2172.                 : c->points[8]) && y >= c->button.TopEdge && y <= c->button.TopEdge + c->points[1] &&
  2173.                 c->hidden == 0 && c->Active)
  2174.             {
  2175.             f = c;
  2176.             c = Gui.FirstFrame;
  2177.             }
  2178.         else
  2179.             c = c->next;
  2180.         }
  2181.     return f;
  2182.     }
  2183.  
  2184. static Frame *FindFrameByMsg(struct IntuiMessage *WinMsg)
  2185.     {
  2186.     Frame *f = Gui.FirstFrame, *RetVal = NULL;
  2187.     while (f)
  2188.         {
  2189.         if (&(f->button) == (struct Gadget *) WinMsg->IAddress && f->hidden == 0)
  2190.             {
  2191.             RetVal = CheckForChildren(f, WinMsg->MouseX, WinMsg->MouseY);
  2192.             break;
  2193.             }
  2194.         f = f->next;
  2195.         }
  2196.     return RetVal;
  2197.     }
  2198.  
  2199. static EditBox *FindEditBoxByWin(struct IntuiMessage *WinMsg)
  2200.    {
  2201.    EditBox *nebl = (WinMsg ? Gui.FirstEditBox : NULL), *RetVal = NULL;
  2202.    while (nebl)
  2203.       {
  2204.       if (&(nebl->editbox) == (struct Gadget *) WinMsg->IAddress)
  2205.          {
  2206.          RetVal = nebl;
  2207.          break;
  2208.          }
  2209.       nebl = nebl->next;
  2210.       }
  2211.    return RetVal;
  2212.    }
  2213.  
  2214. #ifdef NO_LONGER_REQUIRED
  2215. static void StoreSysStatus(void)
  2216.    {
  2217.    PushButton *pb = Gui.GGLfirst;
  2218.    EditBox *eb = Gui.FirstEditBox;
  2219.     GuiWindow *gw = Gui.GWLfirst;
  2220.    while (pb)
  2221.       {
  2222.       pb->SysStatus = pb->Active;
  2223.       pb = pb->Next;
  2224.       }
  2225.    while (eb)
  2226.       {
  2227.       eb->SysStatus = eb->enabled;
  2228.       eb = eb->next;
  2229.       }
  2230.     while (gw)
  2231.         {
  2232.         gw->SysStatus = gw->Enabled;
  2233.         gw = gw->next;
  2234.         }
  2235.    }
  2236.  
  2237. static void RestoreSysStatus(BOOL redraw)
  2238.    {
  2239.    PushButton *pb = Gui.GGLfirst;
  2240.    EditBox *eb = Gui.FirstEditBox;
  2241.     GuiWindow *gw = Gui.GWLfirst;
  2242.    while (pb)
  2243.       {
  2244.       pb->Active = pb->SysStatus;
  2245.       pb = pb->Next;
  2246.       }
  2247.    while (eb)
  2248.       {
  2249.       if (eb->list)
  2250.          {
  2251.          if (eb->SysStatus)
  2252.             EnableDDListBox(eb, redraw);
  2253.          else
  2254.             DisableDDListBox(eb, redraw);
  2255.          }
  2256.         else
  2257.          {
  2258.          if (eb->SysStatus)
  2259.             EnableEditBox(eb, redraw);
  2260.          else
  2261.             DisableEditBox(eb, redraw);
  2262.          }
  2263.       eb = eb->next;
  2264.       }
  2265.     while (gw)
  2266.         {
  2267.         gw->Enabled = gw->SysStatus;
  2268.         gw = gw->next;
  2269.         }
  2270.    }
  2271. #endif
  2272.  
  2273. static void ReplyAllMessages(void)
  2274.     {
  2275.    struct IntuiMessage *WinMsg;
  2276.    GuiWindow *TempWindow = Gui.GWLfirst;
  2277.    while (TempWindow)
  2278.       {
  2279.       while ((WinMsg = (struct IntuiMessage *) GetMsg(TempWindow->Win->UserPort)) != NULL)
  2280.          ReplyMsg((struct Message *) WinMsg);
  2281.       TempWindow = TempWindow->next;
  2282.       }
  2283.     }
  2284.  
  2285. static short gm_result;
  2286. static PushButton *YesButton, *NoButton, *CancelButton;
  2287.  
  2288. int EndGuiMessage(PushButton *pb)
  2289.     {
  2290.     if (pb == NoButton)
  2291.         gm_result = GM_NO;
  2292.     else if (pb == CancelButton)
  2293.         gm_result = GM_CANCEL;
  2294.     else if (pb == YesButton)
  2295.         gm_result = GM_YES;
  2296.     else
  2297.         gm_result = 0;
  2298.     return GUI_MODAL_END;
  2299.     }
  2300.  
  2301. //short ExclamationDataWhite1[] = { 17,0, 9,0, 8,1, 7,1, 6,2, 5,2, 2,5, 2,6, 1,7, 1,8, 0,9, 0,14, 1,15, 1,16, 2,17, 2,18, 5,21, 6,21, 7,22,
  2302. //                                            16,22, 17,21, 18,21, 19,20, 20,20, 22,18, 22,17, 23,16, 23,15, 24,14, 24,9, 23,8, 23,7, 22,6, 22,5, 20,3, 19,3, 18,2 };
  2303. //short ExclamationDataBlack1[] = { 8,23, 16,23, 17,22, 18,22, 19,21, 20,21, 23,18, 23,17, 24,16, 24,15, 25,14, 25,9, 24,8, 24,7, 23,6, 23,5, 20,2, 19,2,
  2304. //                                            18,1, 9,1, 8,2, 7,2, 6,3, 5,3, 3,5, 3,6, 2,7, 2,8, 1,9, 1,14, 2,15, 2,16, 3,17, 3,18, 5,20, 6,20, 7,21 };
  2305.  
  2306. short ExclamationDataWhite2[] = { 12,3, 12,4, 11,5, 11,6, 10,7, 10,8, 9,9, 9,10, 11,12, 11,13, 12,14 };
  2307. short ExclamationDataBlack2[] = { 13,3, 13,4, 14,5, 14,6, 15,7, 15,8, 16,9, 16,10, 14,12, 14,13, 13,14 };
  2308. short ExclamationDataWhite3[] = { 13,17, 12,17, 11,18, 11,19 };
  2309. short ExclamationDataBlack3[] = { 12,20, 13,20, 14,19, 14,18 };
  2310.  
  2311. //short StopDataWhite1[] = { 18,0, 9,0, 8,1, 7,1, 6,2, 5,2, 2,5, 2,6, 1,7, 1,8, 0,9, 0,14, 1,15, 1,16, 2,17, 2,18, 5,21, 6,21, 7,22,
  2312. //                                    17,22, 18,21, 19,21, 20,20, 21,20, 23,18, 23,17, 24,16, 24,15, 25,14, 25,9, 24,8, 24,7, 23,6, 23,5, 21,3, 20,3, 19,2 };
  2313. //short StopDataBlack1[] = { 8,23, 17,23, 18,22, 19,22, 20,21, 21,21, 24,18, 24,17, 25,16, 25,15, 26,14, 26,9, 25,8, 25,7, 24,6, 24,5, 21,2, 20,2,
  2314. //                                    19,1, 9,1, 8,2, 7,2, 6,3, 5,3, 3,5, 3,6, 2,7, 2,8, 1,9, 1,14, 2,15, 2,16, 3,17, 3,18, 5,20, 6,20, 7,21 };
  2315.  
  2316. // White Stop Data must be drawn before black stop data.
  2317. short StopDataWhite2[] = { 5,8, 3,8, 3,11, 6,11, 5,11, 5,14, 3,14, 3,15 };
  2318. short StopDataWhite3[] = { 10,8, 8,8, 8,9, 9,9, 9,14 };
  2319. short StopDataWhite4[] = { 16,8, 13,8, 13,14, 16,14, 16,10 };
  2320. short StopDataWhite5[] = { 21,11, 22,11, 22,8, 19,8, 19,14 };
  2321. short StopDataBlack2[] = { 6,9, 4,9, 4,12, 6,12, 6,15, 4,15 };
  2322. short StopDataBlack3[] = { 9,9, 11,9, 10,9, 10,15 };
  2323. short StopDataBlack4[] = { 14,9, 17,9, 17,15, 14,15, 14,9 };
  2324. short StopDataBlack5[] = { 20,15, 20,9, 23,9, 23,12, 20,12 };
  2325.  
  2326. short XDataWhite1[] = { 6,5, 12,11, 18,5 };
  2327. short XDataWhite2[] = { 6,18, 12,12, 18,18 };
  2328. short XDataBlack1[] = { 7,5, 13,11, 19,5 };
  2329. short XDataBlack2[] = { 7,18, 13,12, 19,18 };
  2330.  
  2331. short QuestionDataWhite1[] = { 13,3, 10,3, 9,4, 9,5, 10,6, 12,6, 14,8, 14,10, 11,13, 11,14 };
  2332. short QuestionDataBlack1[] = { 14,4, 17,7, 17,10, 14,13, 14,14, 13,15, 12,15 };
  2333. short QuestionDataWhite2[] = { 13,17, 12,17, 11,18, 11,19 };
  2334. short QuestionDataBlack2[] = { 12,20, 13,20, 14,19, 14,18 };
  2335.  
  2336. short XBonesDataWhite1[] = { 15,3, 10,3, 8,5, 8,6, 7,7, 7,8, 8,9, 8,10, 9,11, 9,12, 10,13 };
  2337. short XBonesDataWhite2[] = { 10,9, 11,8 };
  2338. short XBonesDataWhite3[] = { 15,9, 16,8 };
  2339. short XBonesDataWhite4[] = { 12,12, 13,12 };
  2340. short XBonesDataWhite5[] = { 17,19, 16,19, 15,18, 14,18 };
  2341. short XBonesDataWhite6[] = { 8,19, 9,19, 10,18, 11,18, 14,15, 15,15, 16,14, 17,14 };
  2342. short XBonesDataWhite7[] = { 8,14, 9,14, 10,15, 11,15, 12,16 };
  2343. short XBonesDataBlack1[] = { 16,4, 17,5, 17,6, 18,7, 18,8, 17,9, 17,10, 16,11, 16,12, 14,14, 11,14 };
  2344. short XBonesDataBlack2[] = { 9,8, 10,7 };
  2345. short XBonesDataBlack3[] = { 14,8, 15,7 };
  2346. short XBonesDataBlack4[] = { 11,12, 11,11, 13,11 };
  2347. short XBonesDataBlack5[] = { 8,15, 9,15, 10,16, 11,16 };
  2348. short XBonesDataBlack6[] = { 8,20, 9,20, 10,19, 11,19, 14,16, 15,16, 16,15, 17,15 };
  2349. short XBonesDataBlack7[] = { 17,20, 16,20, 15,19, 14,19, 13,18 };
  2350.  
  2351. // Points for information icon
  2352. short InfoDataWhite1[] = { 12,5, 12,4, 13,3, 14,3 };short InfoDataBlack1[] = { 13,6, 14,6, 15,5, 15,4 };
  2353. short InfoDataWhite2[] = { 9,18, 9,16, 10,15, 10,12, 11,11, 11,9, 12,8, 13,8 };
  2354. short InfoDataBlack2[] = { 14,9, 14,11, 13,12, 13,15, 12,16, 12,18, 11,19, 10,19 };
  2355.  
  2356. short SingleOutlineDataWhite[] = { 16,0, 9,0, 8,1, 7,1, 6,2, 5,2, 2,5, 2,6, 1,7, 1,8, 0,9, 0,14, 1,15, 1,16, 2,17, 2,18, 5,21, 6,21, 7,22, 8,22 };
  2357. short SingleOutlineDataBlack[] = { 9,23, 16,23, 17,22, 18,22, 19,21, 20,21, 23,18, 23,17, 24,16, 24,15, 25,14, 25,9, 24,8, 24,7, 23,6, 23,5, 20,2, 19,2, 18,1, 17,1 };
  2358.  
  2359. short WideSingleOutlineDataWhite[] = { 17,0, 9,0, 8,1, 7,1, 6,2, 5,2, 2,5, 2,6, 1,7, 1,8, 0,9, 0,14, 1,15, 1,16, 2,17, 2,18, 5,21, 6,21, 7,22, 8,22 };
  2360. short WideSingleOutlineDataBlack[] = { 9,23, 17,23, 18,22, 19,22, 20,21, 21,21, 24,18, 24,17, 25,16, 25,15, 26,14, 26,9, 25,8, 25,7, 24,6, 24,5, 21,2, 20,2, 19,1, 18,1 };
  2361.  
  2362. short FOXLIB GuiMessage(REGA0 void *Scr, REGA1 char *text, REGA2 char *title, REGD0 int detail, REGD1 int block,
  2363.         REGD2 int flags)
  2364.    {
  2365.     int l, lines = 1, height, fontheight, itextlen;
  2366.    GuiWindow *TempWindow;
  2367.     long width, scrwidth, scrheight, minwidth = 200;
  2368.     struct IntuiText ErrorMessage;
  2369.     char *buffer, *c;
  2370.     BOOL bIcon = ((flags & GM_EXCLAMATION) || (flags & GM_QUESTION) || (flags & GM_STOP) || (flags & GM_X) || (flags & GM_CROSSBONES) || (flags & GM_INFORMATION));
  2371.  
  2372.     Diagnostic("GuiMessage", ENTER, TRUE);
  2373.  
  2374.     ErrorMessage.FrontPen = detail;
  2375.     ErrorMessage.DrawMode = JAM1;
  2376.     if (!Scr)
  2377.         {
  2378.         Diagnostic("GuiMessage", EXIT, FALSE);
  2379.         return -1;
  2380.         }
  2381.     else if (ISGUISCREEN(Scr))
  2382.         {
  2383.         scrwidth = ((GuiScreen *) Scr)->scr->Width;
  2384.         scrheight = ((GuiScreen *) Scr)->scr->Height;
  2385.         ErrorMessage.ITextFont = ((GuiScreen *) Scr)->nsc->Font;
  2386.         }
  2387.     else
  2388.         {
  2389.         // Scr must be the name of a public screen.
  2390.         struct Screen *sc = LockPubScreen((char *) Scr);
  2391.         if (sc)
  2392.             {
  2393.             scrwidth = sc->Width;
  2394.             scrheight = sc->Height;
  2395.             ErrorMessage.ITextFont = sc->Font;
  2396.             UnlockPubScreen((char *) Scr, sc);
  2397.             }
  2398.         else
  2399.             {
  2400.             Diagnostic("GuiMessage", EXIT, FALSE);
  2401.             return -1;
  2402.             }
  2403.         }
  2404.     fontheight = ErrorMessage.ITextFont->ta_YSize;
  2405.     ErrorMessage.TopEdge = (2 * fontheight) + 4;
  2406.  
  2407.     buffer = (char*) GuiMalloc((strlen(text) + 1) * sizeof(char), 0);
  2408.     if (!buffer)
  2409.         {
  2410.         Diagnostic("GuiMessage", EXIT, FALSE);
  2411.         return -1;
  2412.         }
  2413.  
  2414.     // strlen returns an unsigned int so strlen("") - 1 is huge (not -1).
  2415.     //    casting to an int solves the problem.
  2416.     for (l = 0; l < ((int) strlen(text)) - 1; l++)
  2417.         if (text[l] == '\n')
  2418.             lines++;
  2419.     height = ((lines + 3) * fontheight) + 25;
  2420.     height = max(height, 55 + fontheight);
  2421.     height = min(height, scrheight);
  2422.     strcpy(buffer, text);
  2423.     c = buffer;
  2424.     width = 0;
  2425.     while (c)
  2426.         {
  2427.         ErrorMessage.IText = c;
  2428.         c = strchr(c, '\n');
  2429.         if (c)
  2430.             *c = 0;
  2431.         itextlen = IntuiTextLength(&ErrorMessage);
  2432.         width = max(width, itextlen);
  2433.         if (c)
  2434.             {
  2435.             *c = '\n';
  2436.             c = &c[1];
  2437.             }
  2438.         }
  2439.     ErrorMessage.NextText = NULL;
  2440.     if ((flags & GM_YES) && (flags & GM_NO) && (flags & GM_CANCEL))
  2441.         minwidth = 280;
  2442.     if (bIcon)
  2443.         width += 72;
  2444.     width = max(width + 20, minwidth);
  2445.     width = min(width, scrwidth);
  2446.  
  2447.    if ((TempWindow = OpenGuiWindow(Scr, (scrwidth - width) /2, (scrheight - height) /2, width, height, detail, block, title, GW_DRAG, NULL, NULL)) != NULL)
  2448.       {
  2449.         int l1 = 10, l2 = (width / 2) - 40, l3 = width - 90, buttons = 0;
  2450.  
  2451.         c = buffer;
  2452.         while (c && ErrorMessage.TopEdge < height - 21 - fontheight) // Leave room for the button.
  2453.             {
  2454.             ErrorMessage.IText = c;
  2455.             c = strchr(c, '\n');
  2456.             if (c)
  2457.                 *c = 0;
  2458.             ErrorMessage.LeftEdge = (width - IntuiTextLength(&ErrorMessage)) / 2;
  2459.             PrintIText(TempWindow->Win->RPort, &ErrorMessage, 0, 0);
  2460.             ErrorMessage.TopEdge += fontheight;
  2461.             if (c)
  2462.                 {
  2463.                 *c = '\n';
  2464.                 c = &c[1];
  2465.                 }
  2466.             }
  2467.  
  2468.         if (flags & GM_YES)
  2469.             buttons ++;
  2470.         if (flags & GM_NO)
  2471.             buttons ++;
  2472.         if (flags & GM_CANCEL)
  2473.             buttons ++;
  2474.  
  2475.         if (buttons < 2)
  2476.             l1 = l2;
  2477.         else if (buttons < 3)
  2478.             l2 = l3;
  2479.  
  2480.         if (flags & GM_YES)
  2481.             if (!(YesButton = MakeButton(TempWindow, (flags & GM_NO ? "_Yes" : "_Okay"), l1, -fontheight - 13, 80, fontheight + 8, (flags & GM_NO ? 'y' : 'o'), NULL, EndGuiMessage, BN_CLEAR | BN_STD | BN_OKAY, NULL)))
  2482.                 {
  2483.                 CloseGuiWindow(TempWindow);
  2484.                 return Diagnostic("GuiMessage", EXIT, FALSE);
  2485.                 }
  2486.         if (flags & GM_NO)
  2487.             if (!(NoButton = MakeButton(TempWindow, "_No", l2, -fontheight - 13, 80, fontheight + 8, 'n', NULL, EndGuiMessage, BN_CLEAR | BN_STD | (flags & GM_CANCEL ? 0 : BN_CANCEL), NULL)))
  2488.                 {
  2489.                 DestroyWinButtons(TempWindow, FALSE);
  2490.                 CloseGuiWindow(TempWindow);
  2491.                 return Diagnostic("GuiMessage", EXIT, FALSE);
  2492.                 }
  2493.         if (flags & GM_CANCEL)
  2494.             if (!(CancelButton = MakeButton(TempWindow, "_Cancel", l3, -fontheight - 13, 80, fontheight + 8, 'c', NULL, EndGuiMessage, BN_CLEAR | BN_STD | BN_CANCEL, NULL)))
  2495.                 {
  2496.                 DestroyWinButtons(TempWindow, FALSE);
  2497.                 CloseGuiWindow(TempWindow);
  2498.                 return Diagnostic("GuiMessage", EXIT, FALSE);
  2499.                 }
  2500.  
  2501.         if (flags & GM_EXCLAMATION)
  2502.         {
  2503.             DrawRPLines(TempWindow->Win->RPort, SingleOutlineDataWhite, 20, Gui.HiPen, JAM1, 8, 16);
  2504.             DrawRPLines(TempWindow->Win->RPort, SingleOutlineDataBlack, 20, Gui.LoPen, JAM1, 8, 16);
  2505.             DrawRPLines(TempWindow->Win->RPort, ExclamationDataWhite2, 11, Gui.HiPen, JAM1, 8, 16);
  2506.             DrawRPLines(TempWindow->Win->RPort, ExclamationDataWhite3, 4, Gui.HiPen, JAM1, 8, 16);
  2507.             DrawRPLines(TempWindow->Win->RPort, ExclamationDataBlack2, 11, Gui.LoPen, JAM1, 8, 16);
  2508.             DrawRPLines(TempWindow->Win->RPort, ExclamationDataBlack3, 4, Gui.LoPen, JAM1, 8, 16);
  2509.         }
  2510.         else if (flags & GM_STOP)
  2511.         {
  2512.             DrawRPLines(TempWindow->Win->RPort, WideSingleOutlineDataWhite, 20, Gui.HiPen, JAM1, 8, 16);
  2513.             DrawRPLines(TempWindow->Win->RPort, WideSingleOutlineDataBlack, 20, Gui.LoPen, JAM1, 8, 16);
  2514.             DrawRPLines(TempWindow->Win->RPort, StopDataWhite2, 8, Gui.HiPen, JAM1, 8, 16);
  2515.             DrawRPLines(TempWindow->Win->RPort, StopDataWhite3, 5, Gui.HiPen, JAM1, 8, 16);
  2516.             DrawRPLines(TempWindow->Win->RPort, StopDataWhite4, 5, Gui.HiPen, JAM1, 8, 16);
  2517.             DrawRPLines(TempWindow->Win->RPort, StopDataWhite5, 5, Gui.HiPen, JAM1, 8, 16);
  2518.             DrawRPLines(TempWindow->Win->RPort, StopDataBlack2, 6, Gui.LoPen, JAM1, 8, 16);
  2519.             DrawRPLines(TempWindow->Win->RPort, StopDataBlack3, 4, Gui.LoPen, JAM1, 8, 16);
  2520.             DrawRPLines(TempWindow->Win->RPort, StopDataBlack4, 5, Gui.LoPen, JAM1, 8, 16);
  2521.             DrawRPLines(TempWindow->Win->RPort, StopDataBlack5, 5, Gui.LoPen, JAM1, 8, 16);
  2522.         }
  2523.         else if (flags & GM_X)
  2524.         {
  2525.             DrawRPLines(TempWindow->Win->RPort, SingleOutlineDataWhite, 20, Gui.HiPen, JAM1, 8, 16);
  2526.             DrawRPLines(TempWindow->Win->RPort, SingleOutlineDataBlack, 20, Gui.LoPen, JAM1, 8, 16);
  2527.             DrawRPLines(TempWindow->Win->RPort, XDataWhite1, 3, Gui.HiPen, JAM1, 8, 16);
  2528.             DrawRPLines(TempWindow->Win->RPort, XDataBlack1, 3, Gui.LoPen, JAM1, 8, 16);
  2529.             DrawRPLines(TempWindow->Win->RPort, XDataWhite2, 3, Gui.HiPen, JAM1, 8, 16);
  2530.             DrawRPLines(TempWindow->Win->RPort, XDataBlack2, 3, Gui.LoPen, JAM1, 8, 16);
  2531.         }
  2532.         else if (flags & GM_QUESTION)
  2533.         {
  2534.             DrawRPLines(TempWindow->Win->RPort, WideSingleOutlineDataWhite, 20, Gui.HiPen, JAM1, 8, 16);
  2535.             DrawRPLines(TempWindow->Win->RPort, WideSingleOutlineDataBlack, 20, Gui.LoPen, JAM1, 8, 16);
  2536.             DrawRPLines(TempWindow->Win->RPort, QuestionDataWhite1, 10, Gui.HiPen, JAM1, 8, 16);
  2537.             DrawRPLines(TempWindow->Win->RPort, QuestionDataBlack1, 7, Gui.LoPen, JAM1, 8, 16);
  2538.             DrawRPLines(TempWindow->Win->RPort, QuestionDataWhite2, 4, Gui.HiPen, JAM1, 8, 16);
  2539.             DrawRPLines(TempWindow->Win->RPort, QuestionDataBlack2, 4, Gui.LoPen, JAM1, 8, 16);
  2540.         }
  2541.         else if (flags & GM_CROSSBONES)
  2542.         {
  2543.             DrawRPLines(TempWindow->Win->RPort, SingleOutlineDataWhite, 20, Gui.HiPen, JAM1, 8, 16);
  2544.             DrawRPLines(TempWindow->Win->RPort, SingleOutlineDataBlack, 20, Gui.LoPen, JAM1, 8, 16);
  2545.             DrawRPLines(TempWindow->Win->RPort, XBonesDataWhite1, 11, Gui.HiPen, JAM1, 8, 16);
  2546.             DrawRPLines(TempWindow->Win->RPort, XBonesDataBlack1, 11, Gui.LoPen, JAM1, 8, 16);
  2547.             DrawRPLines(TempWindow->Win->RPort, XBonesDataWhite2, 2, Gui.HiPen, JAM1, 8, 16);
  2548.             DrawRPLines(TempWindow->Win->RPort, XBonesDataBlack2, 2, Gui.LoPen, JAM1, 8, 16);
  2549.             DrawRPLines(TempWindow->Win->RPort, XBonesDataWhite3, 2, Gui.HiPen, JAM1, 8, 16);
  2550.             DrawRPLines(TempWindow->Win->RPort, XBonesDataBlack3, 2, Gui.LoPen, JAM1, 8, 16);
  2551.             DrawRPLines(TempWindow->Win->RPort, XBonesDataWhite4, 2, Gui.HiPen, JAM1, 8, 16);
  2552.             DrawRPLines(TempWindow->Win->RPort, XBonesDataBlack4, 3, Gui.LoPen, JAM1, 8, 16);
  2553.             DrawRPLines(TempWindow->Win->RPort, XBonesDataWhite5, 4, Gui.HiPen, JAM1, 8, 16);
  2554.             DrawRPLines(TempWindow->Win->RPort, XBonesDataBlack5, 4, Gui.LoPen, JAM1, 8, 16);
  2555.             DrawRPLines(TempWindow->Win->RPort, XBonesDataWhite6, 8, Gui.HiPen, JAM1, 8, 16);
  2556.             DrawRPLines(TempWindow->Win->RPort, XBonesDataBlack6, 8, Gui.LoPen, JAM1, 8, 16);
  2557.             DrawRPLines(TempWindow->Win->RPort, XBonesDataWhite7, 5, Gui.HiPen, JAM1, 8, 16);
  2558.             DrawRPLines(TempWindow->Win->RPort, XBonesDataBlack7, 5, Gui.LoPen, JAM1, 8, 16);
  2559.         }
  2560.         else if (flags & GM_INFORMATION)
  2561.         {
  2562.             DrawRPLines(TempWindow->Win->RPort, SingleOutlineDataWhite, 20, Gui.HiPen, JAM1, 8, 16);
  2563.             DrawRPLines(TempWindow->Win->RPort, SingleOutlineDataBlack, 20, Gui.LoPen, JAM1, 8, 16);
  2564.             DrawRPLines(TempWindow->Win->RPort, InfoDataWhite1, 4, Gui.HiPen, JAM1, 8, 16);
  2565.             DrawRPLines(TempWindow->Win->RPort, InfoDataBlack1, 4, Gui.LoPen, JAM1, 8, 16);
  2566.             DrawRPLines(TempWindow->Win->RPort, InfoDataWhite2, 8, Gui.HiPen, JAM1, 8, 16);
  2567.             DrawRPLines(TempWindow->Win->RPort, InfoDataBlack2, 8, Gui.LoPen, JAM1, 8, 16);
  2568.         }
  2569.  
  2570.         gm_result = 0;
  2571.         WinMsgLoop(TempWindow);
  2572.  
  2573.         DestroyWinButtons(TempWindow, FALSE);
  2574.       CloseGuiWindow(TempWindow);
  2575.         GuiFree(buffer);
  2576.        Diagnostic("GuiMessage", EXIT, TRUE);
  2577.         return gm_result;
  2578.       }
  2579.     return Diagnostic("GuiMessage", EXIT, FALSE);
  2580.    }
  2581.  
  2582. static void CloseNewDDListBox(struct DDListBoxStruct *lbs)
  2583.     {
  2584.     if (lbs)
  2585.         if (lbs->win && lbs->nlb)
  2586.             {
  2587.             DestroyListBox(lbs->nlb, FALSE);
  2588.             lbs->nlb = NULL;
  2589.             CloseGuiWindow(lbs->win);
  2590.             lbs->win = NULL;
  2591.             }
  2592.     }
  2593.  
  2594. static ListBox *NewDDListSelect = NULL;
  2595.  
  2596. int NewDDListTrigger(ListBox *lb, short Event, int HiNum, void **Data)
  2597.     {
  2598.     NewDDListSelect = lb;
  2599.     EscapeKey = FALSE;
  2600.     return GUI_CONTINUE;
  2601.     }
  2602.  
  2603. int NewDDListBoxSelFn(ListBox *lb)
  2604.     {
  2605.     Diagnostic("NewDDListBoxSelFn", ENTER, TRUE);
  2606.  
  2607.     NewDDListSelect = NULL;
  2608.     editptr = NewDDListBoxItemSelect(EscapeKey, NULL);
  2609.     if (!editptr)
  2610.         {
  2611.         // This call to ActivateGadget sometimes fails even though it claims
  2612.         // to succeed!
  2613.         if (Gui.LibVersion >= A3000)
  2614.             if (!ActivateGadget(&NewTopBox->editbox, ((GuiWindow *) NewTopBox->editbox.UserData)->Win, NULL))
  2615.                 SetLastErr("ActivateGadget failed");
  2616.         }
  2617.  
  2618.     Diagnostic("NewDDListBoxSelFn", EXIT, TRUE);
  2619.     return GUI_CONTINUE;
  2620.     }
  2621.  
  2622. #define DD_L_BORDER 2
  2623.  
  2624. static void DropList(struct EditBoxStruct *p)
  2625.     {
  2626.     int width, incrX, incrY, count = 0, winheight;
  2627.     struct ListElement *f;
  2628.     unsigned short fontheight;
  2629.     struct TextAttr *font = &GuiFont; //((GuiWindow *) p->editbox.UserData)->ParentScreen->Font;
  2630.  
  2631.     fontheight = GuiFont.ta_YSize; //GetFontHeight((GuiWindow *) p->editbox.UserData);
  2632.     winheight = (p->list->MaxHeight * fontheight) + 4;
  2633.  
  2634.     f = p->list->first;
  2635.     while (f)
  2636.         {
  2637.         f = f->Next;
  2638.         count++;
  2639.         }
  2640.  
  2641.     if (!p->list->Parent)
  2642.         {
  2643.         int hipen = p->bb1.FrontPen;
  2644.  
  2645.         p->bb1.FrontPen = p->bb2.FrontPen;
  2646.         p->bb2.FrontPen = hipen;
  2647.         RefreshEditBox(p);
  2648.         p->bb2.FrontPen = p->bb1.FrontPen;
  2649.         p->bb1.FrontPen = hipen;
  2650.         NewTopBox = p;
  2651.         }
  2652.     if (p->list->PopupWidth)
  2653.         {
  2654.         Gui.DDListY = p->list->PopupY;
  2655.         incrX = incrY = 0;
  2656.         if (p->list->PopupWidth == -1)
  2657.             { // Attempt to make the list box wide enough to display the longest item.
  2658.             int maxwidth = 0;
  2659.             struct ListElement *le = p->list->first;
  2660.             struct IntuiText it;
  2661.  
  2662.             it.ITextFont = font;
  2663.             while (le)
  2664.                 {
  2665.                 it.IText = le->string;
  2666.                 width = IntuiTextLength(&it);
  2667.                 if (width > maxwidth)
  2668.                     maxwidth = width;
  2669.                 le = le->Next;
  2670.                 }
  2671.             /*    The width is calculated below using the reverse of the formula used in ListBox.c to
  2672.                 calculate the maximum IntuiTextLength from the list box width supplied.  If either
  2673.                 piece of code changes then the other must change to match. */
  2674.             width = maxwidth + (count > p->list->MaxHeight ? SCROLL_BUTTON_WIDTH : 0) + (2 * DD_L_BORDER) + 4;
  2675.             if (width > ((GuiWindow *) p->editbox.UserData)->ParentScreen->Width)
  2676.                 width = ((GuiWindow *) p->editbox.UserData)->ParentScreen->Width;
  2677.             Gui.DDListX = (((GuiWindow *) p->editbox.UserData)->ParentScreen->Width - width)/2;
  2678.             }
  2679.         else
  2680.             {
  2681.             Gui.DDListX = p->list->PopupX;
  2682.             width = p->list->PopupWidth;
  2683.             }
  2684.         }
  2685.     else
  2686.         {
  2687.         Gui.DDListX = ((GuiWindow *) p->editbox.UserData)->Win->LeftEdge;
  2688.         Gui.DDListY = ((GuiWindow *) p->editbox.UserData)->Win->TopEdge;
  2689.         incrX = p->WidgetData->left;
  2690.         incrY = p->WidgetData->top + fontheight + 2;
  2691.  
  2692.         if (Gui.DDListY + incrY + winheight > ((GuiWindow *) p->editbox.UserData)->ParentScreen->Height)
  2693.             incrY = p->WidgetData->top - winheight;
  2694.         width = p->WidgetData->width + DD_LIST_BOX_BUTTON_WIDTH;
  2695.         }
  2696.     Gui.DroppingList = TRUE;
  2697.     // Remember to change SetDDListBoxPopup() in editbox.c if this changes.
  2698.     p->list->win = CreateGuiWindow((GuiScreen *) (((GuiWindow *) p->editbox.UserData)->WidgetData->Parent),
  2699.         ((GuiWindow *) p->editbox.UserData)->ParentScreen, Gui.DDListX + incrX, Gui.DDListY + incrY,
  2700.         width, winheight, p->lborder.FrontPen, p->Bcol, NULL, GW_BORDERLESS, NULL);
  2701.  
  2702.     Gui.DroppingList = FALSE;
  2703.     if (p->list->win)
  2704.         {
  2705.         int flags = 0, num = 1, hinum = 1, start = 1, cmplen = p->buffer ? strlen(GetEditBoxText(p)) : 0;
  2706.  
  2707.         if (count > p->list->MaxHeight)
  2708.             flags = SYS_LB_VSCROLL;
  2709.         p->list->nlb = CreateListBox(p->list->win, p->list->win->Win->BorderLeft,
  2710.             p->list->win->Win->BorderTop,
  2711.             width - p->list->win->Win->BorderRight - p->list->win->Win->BorderLeft,
  2712.             winheight - p->list->win->Win->BorderBottom - p->list->win->Win->BorderTop, DD_L_BORDER, 1,
  2713.             p->Tcol, font, NewDDListTrigger, flags | S_AUTO_SIZE | LB_SELECT, ListBoxObject);
  2714.         Gui.ListFocusOnly = FALSE;
  2715.         f = p->list->first;
  2716.         while (f)
  2717.             {
  2718.             AddListBoxItem(p->list->nlb, f->string, FALSE);
  2719.             if (cmplen > 0 && !strncmp(GetEditBoxText(p), f->string, cmplen))
  2720.                 hinum = num;
  2721.             f = f->Next;
  2722.             num++;
  2723.             }
  2724.         while (hinum > p->list->MaxHeight + start - 1)
  2725.             start++;
  2726.         editptr = p;
  2727.         SetListBoxTopNum(p->list->nlb, start, FALSE);
  2728.         SetListBoxHiNum(p->list->nlb, hinum, TRUE);
  2729.         }
  2730.     else
  2731.         SetLastErr("Unable to open window for drop-down list box.");
  2732. }
  2733.  
  2734. static unsigned int CheckForChars(unsigned long signals, int *lchptr)
  2735.    {
  2736.    unsigned int SigRec = 0L;
  2737.    GuiWindow *gwl = Gui.GWLfirst;
  2738.    while (gwl)
  2739.       {
  2740.       if (signals & gwl->ConReadSig)
  2741.          {
  2742.          *lchptr = ConMayGetChar(gwl->Con, &(Gui.ibuf));
  2743.          SigRec |= gwl->ConReadSig;
  2744.          break;
  2745.          }
  2746.       gwl = gwl->next;
  2747.       }
  2748.    return SigRec;
  2749.    }
  2750.  
  2751. static EditBox *endedit(void)
  2752.     {
  2753.     Diagnostic("endedit", ENTER, TRUE);
  2754.     EditBoxSelected(NULL);
  2755.     Diagnostic("endedit", EXIT, TRUE);
  2756.     return editptr;
  2757.     }
  2758.  
  2759. static void ProcessKeys(unsigned char *CharStream, GuiWindow *MsgWin, GuiWindow *ModalWin)
  2760.     {
  2761.     BOOL csi = FALSE;
  2762.     int i = 0;
  2763.  
  2764.     while (i < strlen((char*) CharStream) && (!Stop & GUI_END))
  2765.         {
  2766.         unsigned char ch = CharStream[i++];
  2767.  
  2768.         if (ch == VAL_CSI)
  2769.             {
  2770.             csi = TRUE;
  2771.             continue;
  2772.             }
  2773.         if (csi)
  2774.             {
  2775.             // Process cursor keys et al.
  2776.             if ((ch == 'A' || ch == 'B') && (MsgWin == ModalWin || ModalWin == NULL)) // Cursor up/down.
  2777.                 {
  2778.                 // Check to see whether there's a list box in this window that we can scroll
  2779.                 register int h;
  2780.                 ListBox *lb = Gui.FirstListBox;
  2781.                 while (lb)
  2782.                     {
  2783.                     if (lb->Win == MsgWin)
  2784.                         if (ch == 'A')
  2785.                             {
  2786.                             if ((h = HiNum(lb)) > 1)
  2787.                                 {
  2788.                                 SetListBoxHiNum(lb, h - 1, h - 1 >= lb->TopShown);
  2789.                                 if (h - 1 < lb->TopShown)
  2790.                                     ListBoxScrollUp(lb, TRUE);
  2791.                                 if (lb->WidgetData->flags & LB_CURSOR)
  2792.                                     {
  2793.                                     Stop = (*(lb->Eventfn))(lb, LB_CURSOR, lb->HiNum, NULL);
  2794.                                     Gui.Done = TRUE;
  2795.                                     }
  2796.                                 }
  2797.                             }
  2798.                         else
  2799.                             if ((h = HiNum(lb)) < lb->NoItems)
  2800.                                 {
  2801.                                 register int LastShown = lb->TopShown + NumLines(lb) - 1;
  2802.                                 SetListBoxHiNum(lb, h + 1, h + 1 <= LastShown);
  2803.                                 if (h + 1 > LastShown)
  2804.                                     ListBoxScrollDown(lb, TRUE);
  2805.                                 if (lb->WidgetData->flags & LB_CURSOR)
  2806.                                     {
  2807.                                     Stop = (*(lb->Eventfn))(lb, LB_CURSOR, lb->HiNum, NULL);
  2808.                                     Gui.Done = TRUE;
  2809.                                     }
  2810.                                 }
  2811.                     lb = lb->NextListBox;
  2812.                     }
  2813.                 }
  2814.             csi = FALSE;
  2815.             }
  2816.         else
  2817.             {
  2818.             // If a drop-down list box is active
  2819.             if (editptr && editptr->list && editptr->list->win && editptr->list->nlb)
  2820.                 {
  2821.                 if (ch == VAL_ESC)
  2822.                     {
  2823.                     // Close the drop-down list without selecting anything.
  2824.                     EscapeKey = TRUE;
  2825.                     NewDDListSelect = editptr->list->nlb;
  2826.                     }
  2827.                 else if (ch == VAL_SPC || ch == VAL_CR)
  2828.                     {
  2829.                     // Select the current item and close the drop-down list.
  2830.                     EscapeKey = FALSE;
  2831.                     NewDDListSelect = editptr->list->nlb;
  2832.                     }
  2833.                 else
  2834.                     {
  2835.                     // Hilight the next item starting with the character typed.
  2836.                     struct IntuiText *start = HiElem(editptr->list->nlb), *it = start;
  2837.                     unsigned char altch;
  2838.  
  2839.                     if (isupper(ch))
  2840.                         altch = tolower(ch);
  2841.                     else if (islower(ch))
  2842.                         altch = toupper(ch);
  2843.                     else
  2844.                         altch = ch;
  2845.  
  2846.                     do
  2847.                         {
  2848.                         if (!(it = NextItem(it)))
  2849.                             it = editptr->list->nlb->FirstItem;
  2850.                         } while (it != start && it->IText[0] != ch && it->IText[0] != altch);
  2851.  
  2852.                     if (it != start)
  2853.                         {
  2854.                         // found one!
  2855.                         register int itemnum = ItemNum(editptr->list->nlb, it);
  2856.                         register int numlines = NumLines(editptr->list->nlb);
  2857.  
  2858.                         if (itemnum > 0)
  2859.                             if (itemnum >= editptr->list->nlb->TopShown && itemnum <=
  2860.                                     editptr->list->nlb->TopShown + numlines - 1)
  2861.                                 SetListBoxHiNum(editptr->list->nlb, itemnum, TRUE);
  2862.                             else
  2863.                                 {
  2864.                                 int newtopnum = 1;
  2865.                                 while (itemnum > newtopnum + numlines - 1)
  2866.                                     newtopnum++;
  2867.                                 SetListBoxHiNum(editptr->list->nlb, itemnum, FALSE);
  2868.                                 SetListBoxTopNum(editptr->list->nlb, newtopnum, TRUE);
  2869.                                 }
  2870.                         }
  2871.                     }
  2872.                 }
  2873.             else
  2874.                 {
  2875.                 PushButton *ggl = Gui.GGLfirst;
  2876.  
  2877.                 // Check button hot-keys and default keys (return and escape) for Okay and Cancel buttons.
  2878.                 while (ggl)
  2879.                     {
  2880.                     /*    Don't activate the button if it's not in the modal window (if there is one) or if
  2881.                         it's in a sleeping window. */
  2882.                     if (ggl->Active && (ch == ggl->Key1 || (ch == VAL_CR && (ggl->WidgetData->flags & BN_OKAY)) ||
  2883.                             ch == ggl->Key2 || (ch == VAL_ESC && (ggl->WidgetData->flags & BN_CANCEL))) &&
  2884.                             (! (((GuiWindow *) ggl->button.UserData)->Sleep)) &&
  2885.                             (ModalWin == NULL || ggl->button.UserData == (APTR) ModalWin))
  2886.                         {
  2887.                         /*    We've found a button that could be activated by this key BUT we may not want to
  2888.                             activate it yet.  It could be that there is an edit box active (i.e. editptr non
  2889.                             NULL) even though the key went to the IDCMP not straight to the edit box.  This
  2890.                             would happen if the user had forced intuition to forget about the edit box by (for
  2891.                             example) clicking in another application's window.  If he then re-activates this
  2892.                             application by (for example) clicking on a window's title bar he would then be able
  2893.                             to activate the button with a keypress, leaving the edit box unvalidated.  If that
  2894.                             button destroyed the editbox, next time a button were clicked with a mouse, FoxGui
  2895.                             will try to validate it - result CRASH!  We can prevent all that here if we don't
  2896.                             let the user select that button without first validating the edit box. */
  2897.  
  2898.                         // Check whether there is a currently active edit/drop-down list box.
  2899.                         EditBox *active = editptr ? editptr : lastactiveDDListBox;
  2900.  
  2901.                         if (active)
  2902.                             {
  2903.                             endedit();
  2904.  
  2905.                             // Check whether the validation succeeded (active will be NULL for success).
  2906.                             active = editptr ? editptr : lastactiveDDListBox;
  2907.                             }
  2908.                         /*    Call the buttons click function if there was no validation to do or if the
  2909.                             validation succeeded. */
  2910.                         if (!active)
  2911.                             {
  2912.                             Gui.Done = TRUE;
  2913.                             ActionPtr = ggl;
  2914.                             Action = ACTION_BUTTON;
  2915.                             break;
  2916.                             }
  2917.                         }
  2918.                     ggl = ggl->Next;
  2919.                     }
  2920.                 }
  2921.             }
  2922.         }
  2923.     }
  2924.  
  2925. static GuiWindow *FindWindowBySignal(unsigned long signals, unsigned long *SigRec)
  2926.    {
  2927.     GuiWindow *winptr = NULL, *gwl = Gui.GWLfirst;
  2928.     *SigRec = 0;
  2929.     while (gwl)
  2930.         {
  2931.         if (signals & gwl->WindowSig)
  2932.             {
  2933.             winptr = gwl;
  2934.             *SigRec = gwl->WindowSig;
  2935.             break;
  2936.             }
  2937.         gwl = gwl->next;
  2938.         }
  2939.     return winptr;
  2940.     }
  2941.  
  2942. static GuiWindow *FindWindowByConSignal(unsigned long signals)
  2943.    {
  2944.    GuiWindow *winptr = NULL, *gwl = Gui.GWLfirst;
  2945.    while (gwl)
  2946.       {
  2947.       if (signals & gwl->ConReadSig)
  2948.          {
  2949.          winptr = gwl;
  2950.          break;
  2951.          }
  2952.       gwl = gwl->next;
  2953.       }
  2954.    return winptr;
  2955.    }
  2956.  
  2957. static void ListSelectAndActivate(int NoSelect, struct ListElement *elemfound)
  2958.     {
  2959.     // Select an item in a drop down list and then re-activate the top-level
  2960.     // box.
  2961.     Diagnostic("ListSelectAndActivate", ENTER, TRUE);
  2962.     editptr = DDListBoxItemSelect(NoSelect, elemfound);
  2963.     if (!editptr)
  2964.         {
  2965.         // This call to ActivateGadget sometimes fails even though it claims
  2966.         // to succeed!
  2967.         if (Gui.LibVersion >= A3000)
  2968.             if (!ActivateGadget(&NewTopBox->editbox, ((GuiWindow *) NewTopBox->editbox.UserData)->Win, NULL))
  2969.                 SetLastErr("ActivateGadget failed");
  2970.         }
  2971.     Diagnostic("ListSelectAndActivate", EXIT, TRUE);
  2972.     }
  2973.  
  2974. static DDListBox *DDListBoxItemSelect(BOOL NoSelect, struct ListElement *elemfound)
  2975.     {
  2976.     // elemfound will be true if the item was selected by a keypress without
  2977.     // the listbox dropped.
  2978.     BOOL valid;
  2979.     struct ListElement *element = NULL;
  2980.     DDListBox *fnbox;
  2981.  
  2982.     Diagnostic("DDListBoxItemSelect", ENTER, TRUE);
  2983.     if (elemfound)
  2984.         element = elemfound;
  2985.  
  2986.     if (element && !NoSelect)
  2987.         {
  2988.         if (!(element->Child))
  2989.             SetEditBoxText(NewTopBox, element->string);
  2990.         }
  2991.     else
  2992.         RefreshGList(&NewTopBox->editbox, ((GuiWindow *) NewTopBox->editbox.UserData)->Win, NULL, 1);
  2993.  
  2994.     // editptr will be set if the item was clicked on with a mouse OR
  2995.     // if the item was selected from a sub DDListBox but will NOT be set if
  2996.     // selected by keypress from a top-level list box
  2997.     fnbox = editptr ? editptr : NewTopBox;
  2998.    if (NoSelect || !(fnbox->valifn))
  2999.       valid = TRUE;
  3000.    else
  3001.       valid = (*(fnbox->valifn))(fnbox);
  3002.  
  3003.     if (element && element->Child && !NoSelect)
  3004.         {
  3005.         DropList((DDListBox *) element->Child);
  3006.         Diagnostic("DDListBoxItemSelect", EXIT, TRUE);
  3007.         return (DDListBox *) element->Child;
  3008.         }
  3009.     Diagnostic("DDListBoxItemSelect", EXIT, TRUE);
  3010.     return NULL;
  3011.     }
  3012.  
  3013. static struct EditBoxStruct *nlbHiChild(struct DDListBoxStruct *lbs)
  3014.     {
  3015.     if (lbs)
  3016.         {
  3017.         ListBox *lb = lbs->nlb;
  3018.         if (lb)
  3019.             {
  3020.             int itemnum = HiNum(lb);
  3021.  
  3022.             if (itemnum == 0)
  3023.                 return NULL;
  3024.             else
  3025.                 {
  3026.                 struct ListElement *cle = lbs->first;
  3027.                 while (cle)
  3028.                     {
  3029.                     if (cle->Itemnum == itemnum)
  3030.                         return cle->Child;
  3031.                     cle = cle->Next;
  3032.                     }
  3033.                 }
  3034.             }
  3035.         }
  3036.     return NULL;
  3037.     }
  3038.  
  3039. static DDListBox *NewDDListBoxItemSelect(BOOL NoSelect, struct IntuiText *elemfound)
  3040.     {
  3041.     // elemfound will be true if the item was selected by a keypress without the listbox dropped.
  3042.     BOOL valid;
  3043.     struct IntuiText *element = NULL;
  3044.     DDListBox *fnbox;
  3045.  
  3046.     /*    Closing the new list box will clear out all the data refering to it's list.  We could retrieve
  3047.         the child (if there is one) from the underlying list structure but since the child itself is not
  3048.         destroyed (just our pointer to it) it's far quicker (and easier) to make a note of it's location
  3049.         before we close the list that's currently open. */
  3050.     DDListBox *Child = NULL;
  3051.  
  3052.     Diagnostic("NewDDListBoxItemSelect", ENTER, TRUE);
  3053.  
  3054.     if (!(elemfound || editptr))
  3055.         {
  3056.         Diagnostic("NewDDListBoxItemSelect", EXIT, FALSE);
  3057.         return editptr;
  3058.         }
  3059.  
  3060.     if (elemfound)
  3061.         element = elemfound;
  3062.     else
  3063.         element = HiElem(editptr->list->nlb);
  3064.  
  3065.     if (element)
  3066.         Child = nlbHiChild(editptr->list);
  3067.  
  3068.     if (element && !NoSelect)
  3069.         {
  3070.         if (!Child)
  3071.                 SetEditBoxText(NewTopBox, element->IText);
  3072.         }
  3073.     else
  3074.         RefreshGList(&NewTopBox->editbox, ((GuiWindow *) NewTopBox->editbox.UserData)->Win, NULL, 1);
  3075.  
  3076.     if (!elemfound)
  3077.             CloseNewDDListBox(editptr->list);
  3078.  
  3079.     // editptr will be set if the item was clicked on with a mouse OR
  3080.     // if the item was selected from a sub DDListBox but will NOT be set if
  3081.     // selected by keypress from a top-level list box
  3082.         fnbox = editptr ? editptr : NewTopBox;
  3083.        if (NoSelect || !(fnbox->valifn))
  3084.           valid = TRUE;
  3085.        else
  3086.             {
  3087.             EditBox *editptrcpy = editptr;
  3088.  
  3089.             /*    We need to set editptr to NULL before calling the user's validation function because that
  3090.                 function might (for example) call GuiMessage() which would then run a modal loop on that
  3091.                 window.  If the user then clicked (eg) the Okay button on that window, because editptr was
  3092.                 not NULL it would try to validate this list box before allowing you to click that button.
  3093.                 In that way you could get into an infinite loop, repeatedly trying to validate the list box
  3094.                 whenever you tried to respond to the GuiMessage() window! */
  3095.             editptr = NULL;
  3096.           valid = (*(fnbox->valifn))(fnbox);
  3097.             editptr = editptrcpy;
  3098.             }
  3099.  
  3100.     if (element && Child && !NoSelect)
  3101.         {
  3102.         DropList(Child);
  3103.         Diagnostic("NewDDListBoxItemSelect", EXIT, TRUE);
  3104.         return Child;
  3105.         }
  3106.     Diagnostic("NewDDListBoxItemSelect", EXIT, TRUE);
  3107.     return NULL;
  3108.     }
  3109.  
  3110. static TickBox *FindTickBox(struct IntuiMessage *WinMsg)
  3111.     {
  3112.     TickBox *tb = Gui.FirstTickBox;
  3113.     if (WinMsg)
  3114.         {
  3115.         while (tb)
  3116.             if (&(tb->TickBoxGad) == WinMsg->IAddress)
  3117.                 break;
  3118.             else
  3119.                 tb = tb->Next;
  3120.         }
  3121.     else
  3122.         return NULL;
  3123.     return tb;
  3124.     }
  3125.  
  3126. static ListBox *ListBoxScrollGad(struct IntuiMessage *WinMsg)
  3127.     {
  3128.     ListBox *lb = Gui.FirstListBox;
  3129.     if (WinMsg)
  3130.         {
  3131.         while (lb)
  3132.             if (lb->UD && WinMsg->IAddress == &lb->UD->ScrollGad)
  3133.                 break;
  3134.             else if (lb->LR && WinMsg->IAddress == &lb->LR->ScrollGad)
  3135.                 break;
  3136.             else
  3137.                 lb = lb->NextListBox;
  3138.         }
  3139.     else
  3140.         return NULL;
  3141.     return lb;
  3142.     }
  3143.  
  3144. static void UpdateLBScrollGadImagery(ListBox *lb)
  3145.     {
  3146.     int hi = lb->HiNum, showable = NumLines(lb);
  3147.     unsigned short top = 1;
  3148.  
  3149.     if (lb->UD)
  3150.         top = FindScrollerTop(lb->NoItems, showable, lb->UD->ScrollGadInfo.VertPot) + 1;
  3151.     if (top != lb->TopShown) // Vertical scroller
  3152.         {
  3153.         /*    If the list has only been scrolled 1 line either way then use the appropriate scroll function
  3154.             instead of doing a complete refresh which would be much slower */
  3155.         if (top == lb->TopShown - 1)
  3156.             ListBoxScrollUp(lb, FALSE);
  3157.         else if (top == lb->TopShown + 1)
  3158.             ListBoxScrollDown(lb, FALSE);
  3159.         else
  3160.             {
  3161.             // Do a complete refresh
  3162.             if (hi && (lb->WidgetData->flags & LB_REHILIGHT_ON_SCROLL))
  3163.                 {
  3164.                 if (hi < top)
  3165.                     hi = top;
  3166.                 else if (hi >= top + showable)
  3167.                     hi = top + showable - 1;
  3168.                 if (hi != lb->HiNum)
  3169.                     SetListBoxHiNum(lb, hi, FALSE);
  3170.                 }
  3171.             SetListBoxTopNum(lb, top, TRUE);
  3172.             }
  3173.         }
  3174.     if (lb->LR)
  3175.         {
  3176.         int left = 0 - FindScrollerTop(lb->LongestIntuiLen, lb->MaxIntuiLen, lb->LR->ScrollGadInfo.HorizPot);
  3177.         if (left != lb->xOffset) // Horizontal Scroller
  3178.             {
  3179.             lb->xOffset = left;
  3180.             ListBoxRefresh(lb);
  3181.             }
  3182.         }
  3183.     }
  3184.  
  3185. static BOOL CheckTickBox(struct IntuiMessage *WinMsg)
  3186.     {
  3187.     BOOL retval = FALSE;
  3188.     TickBox *tb = FindTickBox(WinMsg);
  3189.     if (tb)
  3190.         {
  3191.         // Check whether there is a currently active edit/drop-down list box.
  3192.         EditBox *active = editptr ? editptr : lastactiveDDListBox;
  3193.         retval = TRUE;
  3194.  
  3195.         if (active)
  3196.             {
  3197.             EditBoxSelected(WinMsg);
  3198.  
  3199.             // Check whether the validation succeeded (active will be NULL for success).
  3200.             active = editptr ? editptr : lastactiveDDListBox;
  3201.             }
  3202.         // Call the tick boxes click function if there was no validation to do or if the validation succeeded.
  3203.         if (!active)
  3204.             {
  3205.             ActionPtr = tb;
  3206.             Action = ACTION_TICKBOX;
  3207.             Gui.Done = TRUE;
  3208.             }
  3209.         }
  3210.     return retval;
  3211.     }
  3212.  
  3213. void UpdateTCScrollGadImagery(TreeControl *tc);
  3214.  
  3215. static BOOL ListScroll(struct IntuiMessage *WinMsg, GuiWindow *win, ListBox **SelectedLB)
  3216.     {
  3217.     if (win && WinMsg)
  3218.         {
  3219.         /* NOTE: The IAddress comparison below is only valid for GADGETUP and
  3220.             GADGETDOWN messages.  This comparison should not be performed with (eg)
  3221.             MOUSEMOVE messages! */
  3222.  
  3223.         ListBox *lb = ListBoxScrollGad(WinMsg);
  3224.         if (lb)
  3225.             {
  3226.             if (lb->itemlist)
  3227.                 UpdateTCScrollGadImagery(lb);
  3228.             else
  3229.                 UpdateLBScrollGadImagery(lb);
  3230.             *SelectedLB = NULL;
  3231.             if (lb->WidgetData->flags & LB_CURSOR)
  3232.                 if (lb->itemlist) // it's a tree control
  3233.                     {
  3234.                     if (SelectedLBHiItem != (ListBoxItem *) lb->hiitem)
  3235.                         Stop = ((TCIntFnPtr) *(lb->Eventfn))(lb, TC_CURSOR, lb->hiitem, NULL);
  3236.                     }
  3237.                 else if (SelectedLBHiItem != lb->HiItem)
  3238.                     Stop = (*(lb->Eventfn))(lb, LB_CURSOR, lb->HiNum, NULL);
  3239.             Gui.Done = TRUE;
  3240.             return TRUE;
  3241.             }
  3242.         }
  3243.     return FALSE;
  3244.     }
  3245.  
  3246. static BOOL EditBoxSelected(struct IntuiMessage *WinMsg)
  3247.     {
  3248.     BOOL valid = TRUE, FocusSet = FALSE;
  3249.    EditBox *neweb, *ebp;
  3250.     Diagnostic("EditBoxSelected", ENTER, TRUE);
  3251.     ebp = FindEditBoxByWin(WinMsg);
  3252.     neweb = (ebp && ebp->list ? NULL : ebp);
  3253.     if (editptr)
  3254.         {
  3255.         if (editptr->list)
  3256.             {
  3257.             if (editptr->list->win && WinMsg)
  3258.                 neweb = editptr;
  3259.             else
  3260.                 DDListBoxItemSelect(FALSE, NULL);
  3261.             }
  3262.         else
  3263.             {
  3264.             if (editptr->enabled && editptr->valifn && ebp != editptr)
  3265.                 {
  3266.                 EditBox *old = editptr;
  3267.                 /*    Set editptr to NULL so that if another gadget gets activated by the users validation
  3268.                     function (such as when a message box appears and the user clicks the Okay button), this
  3269.                     gadgets validation function won't get fired again. */
  3270.                 editptr = NULL;
  3271.               valid = (*(old->valifn))(old);
  3272.                 /*    Reset editptr after the call to the users validation function but only if it's NULL.  If
  3273.                     it's not NULL, the user called SetEditBoxFocus to set it so we should respect the user's
  3274.                     wishes. */
  3275.                 if (editptr == NULL)
  3276.                     editptr = old;
  3277.                 else
  3278.                     {
  3279.                     neweb = editptr;
  3280.                     FocusSet = TRUE;
  3281.                     }
  3282.                 }
  3283.             /*    Don't set the focus if we've already done it in SetEditBoxFocus() - it's slow enough once -
  3284.                 twice would be ridiculous */
  3285.             if ((!valid) && !FocusSet)
  3286.                 {
  3287.                 neweb = editptr;
  3288.                 DeactivateUnknownEditBox();
  3289.                 ActivateGadget(&editptr->editbox, ((GuiWindow *) editptr->editbox.UserData)->Win, NULL);
  3290.                 }
  3291.             }
  3292.         }
  3293.     editptr = neweb;
  3294.     if (valid)
  3295.         lastactiveDDListBox = (ebp && ebp->list ? ebp : NULL);
  3296.     Diagnostic("EditBoxSelected", EXIT, TRUE);
  3297.     return (BOOL) ((ebp != NULL) || !valid);
  3298.     }
  3299.  
  3300. static Frame *FrameRClick(GuiWindow *winptr, struct IntuiMessage *WinMsg)
  3301.     {
  3302.     Frame *f = Gui.FirstFrame;
  3303.     short MouseX, MouseY;
  3304.  
  3305.     if (!WinMsg)
  3306.         return NULL;
  3307.  
  3308.     MouseX = WinMsg->MouseX + winptr->Win->LeftEdge; // Screen coordinates
  3309.     MouseY = WinMsg->MouseY + winptr->Win->TopEdge;
  3310.  
  3311.     while (f)
  3312.         {
  3313.         GuiWindow *frwin = GetWindow(f);
  3314.         int WinX = MouseX - frwin->Win->LeftEdge, WinY = MouseY - frwin->Win->TopEdge;
  3315.  
  3316.         if ((f->WidgetData->flags & FM_RBUT) && f->hidden == 0 && f->Active && WinX >= f->button.LeftEdge &&
  3317.             WinX <= f->button.LeftEdge + f->points[8] + 1 && WinY >= f->button.TopEdge
  3318.             && WinY <= f->button.TopEdge + f->points[1] + 1)
  3319.             return f;
  3320.         f = f->next;
  3321.         }
  3322.     return NULL;
  3323.     }
  3324.  
  3325. // FoxEd manipulates these variables to do some rubber-banding.
  3326. static int DragOutlineX = -1;
  3327. static int DragOutlineY = -1;
  3328. static int DragStartWidth = 0;
  3329. static int DragStartHeight = 0;
  3330. static int DragMinWidth = 0;
  3331. static int DragMinHeight = 0;
  3332.  
  3333. void FOXLIB SetupSizeOutlineData(REGD0 int x, REGD1 int y, REGD2 int width, REGD3 int height, REGD4 int minwidth, REGD5 int minheight)
  3334.     {
  3335.     DragOutlineX = x;
  3336.     DragOutlineY = y;
  3337.     DragStartWidth = width;
  3338.     DragStartHeight = height;
  3339.     DragMinWidth = minwidth;
  3340.     DragMinHeight = minheight;
  3341.     }
  3342.  
  3343. void DrawSizeOutline(Frame *fm, GuiWindow *winptr, BOOL undraw, BOOL draw, int x, int y)
  3344.     {
  3345.     static short points[10];
  3346.     static int Left, Top;
  3347.  
  3348.     if (draw && !undraw)
  3349.         {
  3350.         // Only update when starting a new drag!
  3351.         if (DragOutlineX == -1)
  3352.             Left = winptr->Win->LeftEdge + fm->button.LeftEdge;
  3353.         else
  3354.             Left = DragOutlineX;
  3355.         if (DragOutlineY == -1)
  3356.             Top = winptr->Win->TopEdge + fm->button.TopEdge;
  3357.         else
  3358.             Top = DragOutlineY;
  3359.         points[0] = Left;
  3360.         points[1] = Top;
  3361.         points[3] = Top;
  3362.         points[6] = Left;
  3363.         points[8] = Left;
  3364.         points[9] = Top + 1;
  3365.         }
  3366.  
  3367.     if (undraw) // Undraw the old border.
  3368.         DrawRPLines(&winptr->ParentScreen->RastPort, points, 5, 1, COMPLEMENT, 0, 0);
  3369.  
  3370.     points[2] = Left + max(DragStartWidth + x, DragMinWidth);
  3371.     points[4] = Left + max(DragStartWidth + x, DragMinWidth);
  3372.     points[5] = Top + max(DragStartHeight + y, DragMinHeight);
  3373.     points[7] = Top + max(DragStartHeight + y, DragMinHeight);
  3374.  
  3375.     if (draw)
  3376.         DrawRPLines(&winptr->ParentScreen->RastPort, points, 5, 1, COMPLEMENT, 0, 0);
  3377.  
  3378.     if (undraw && !draw)
  3379.         {
  3380.         DragOutlineX = DragOutlineY = -1;
  3381.         DragStartWidth = DragStartHeight = 0;
  3382.         }
  3383.     }
  3384.  
  3385. void DrawDragOutline(Frame *fm, GuiWindow *winptr, BOOL undraw, BOOL draw, int x, int y)
  3386.     {
  3387.     static short points[10];
  3388.     static int Left, Top;
  3389.  
  3390.     if (fm->WidgetData->flags & FM_SIZEOUTLINE)
  3391.         {
  3392.         DrawSizeOutline(fm, winptr, undraw, draw, x, y);
  3393.         return;
  3394.         }
  3395.  
  3396.     if (draw && !undraw)
  3397.         {
  3398.         // Only update when starting a new drag!
  3399.         Left = winptr->Win->LeftEdge + fm->button.LeftEdge;
  3400.         Top = winptr->Win->TopEdge + fm->button.TopEdge;
  3401.         }
  3402.  
  3403.     if (undraw) // Undraw the old border.
  3404.         DrawRPLines(&winptr->ParentScreen->RastPort, points, 5, 1, COMPLEMENT, 0, 0);
  3405.  
  3406.     points[0] = Left + x;
  3407.     points[1] = Top + y;
  3408.     points[2] = Left + fm->points[8] + x;
  3409.     points[3] = Top + y;
  3410.     points[4] = Left + fm->points[8] + x;
  3411.     points[5] = Top + fm->points[1] + y;
  3412.     points[6] = Left + x;
  3413.     points[7] = Top + fm->points[1] + y;
  3414.     points[8] = Left + x;
  3415.     points[9] = Top + y + 1;
  3416.  
  3417.     if (draw)
  3418.         DrawRPLines(&winptr->ParentScreen->RastPort, points, 5, 1, COMPLEMENT, 0, 0);
  3419.     }
  3420.  
  3421. static BOOL NormalButtonFramePress(struct IntuiMessage *WinMsg, Frame **FrameDragPtr, Frame **FrameDownPtr)
  3422.    {
  3423.     BOOL retval = FALSE;
  3424.    PushButton *ButtPtr;
  3425.     Frame *FramePtr = NULL;
  3426.  
  3427.     Diagnostic("NormalButtonFramePress", ENTER, TRUE);
  3428.     ButtPtr = FindButtonByMsg(WinMsg);
  3429.     if (!ButtPtr)
  3430.         FramePtr = FindFrameByMsg(WinMsg);
  3431.     if (FramePtr) // The user has released the frame.
  3432.         *FrameDownPtr = NULL;
  3433.     if (FramePtr && *FrameDragPtr)
  3434.         {
  3435.         /*    The user has released a frame that was being dragged while still over the frame itself hence we
  3436.             received a gadget up event rather than a mouse buttons select-up which is what we would have
  3437.             received if the user had released the frame with the pointer anywhere else. */
  3438.         Gui.Done = retval = TRUE;
  3439.         Action = ACTION_DROP;
  3440.         ActionPtr = *FrameDragPtr;
  3441.         ActionX = WinMsg->MouseX;
  3442.         ActionY = WinMsg->MouseY;
  3443.         if ((*FrameDragPtr)->WidgetData->flags & FM_DRAGOUTLINE)
  3444.             DrawDragOutline(*FrameDragPtr, GetWindow(*FrameDragPtr), TRUE,  FALSE, 0, 0);
  3445.         *FrameDragPtr = NULL;
  3446.         }
  3447.     else if ((ButtPtr && ButtPtr->Active) || (FramePtr && FramePtr->Active && (FramePtr->WidgetData->flags & FM_LBUT)))
  3448.       {
  3449.         // Check whether there is a currently active edit/drop-down list box.
  3450.         EditBox *active = editptr ? editptr : lastactiveDDListBox;
  3451.  
  3452.         retval = TRUE;
  3453.         if (active)
  3454.             {
  3455.             EditBoxSelected(WinMsg);
  3456.  
  3457.             // Check whether the validation succeeded (active will be NULL for success).
  3458.             active = editptr ? editptr : lastactiveDDListBox;
  3459.             }
  3460.         // Call the button or frames click function if there was no validation to do or if the validation succeeded.
  3461.       if (!active)
  3462.          {
  3463.             ActionPtr = ButtPtr ? ButtPtr : (PushButton *) FramePtr;
  3464.             ActionX = WinMsg->MouseX;
  3465.             ActionY = WinMsg->MouseY;
  3466.             Action = ButtPtr ? ACTION_BUTTON : ACTION_FRAME_LBUT;
  3467.             Gui.Done = TRUE;
  3468.          }
  3469.       }
  3470.     Diagnostic("NormalButtonFramePress", EXIT, TRUE);
  3471.     return retval;
  3472.    }
  3473.  
  3474. static void RadioButtonClick(RadioButton *rb)
  3475.     {
  3476.     struct MutexList *ActiveRB = rb->MList;
  3477.     unsigned short position;
  3478.  
  3479.     if (rb->RBGad.Flags & GFLG_SELECTED)
  3480.         return; // This one is already selected.  Nothing to do.
  3481.  
  3482.     position = RemoveGadget((struct Window *) rb->RBGad.UserData, &(rb->RBGad));
  3483.     if (position == -1) // RemoveGadget failed!
  3484.         {
  3485.         SetLastErr("RadioButtonClick failed to remove the gadget.");
  3486.         return;
  3487.         }
  3488.  
  3489.     // Find the active member of the group.
  3490.     while (ActiveRB && !(ActiveRB->Mutex->RBGad.Flags & GFLG_SELECTED))
  3491.         ActiveRB = ActiveRB->Next;
  3492.     if (ActiveRB)
  3493.         {
  3494.         struct Gadget *ActiveGad = &(ActiveRB->Mutex->RBGad);
  3495.         // Remove the active gadget
  3496.         unsigned short activepos = RemoveGadget((struct Window *) ActiveGad->UserData, ActiveGad);
  3497.         if (activepos == -1)
  3498.             SetLastErr("RadioButtonClick failed to remove the active gadget.");
  3499.         else
  3500.             {
  3501.             /*    Blank the area (this is to remove the fill points - to save us from having another set
  3502.                 of fill points in the blank colour */
  3503.             AreaBlank(((struct Window *) ActiveGad->UserData)->RPort, ActiveGad->LeftEdge,
  3504.                     ActiveGad->TopEdge, ActiveGad->Width, ActiveGad->Height);
  3505.             // Deactivate it.
  3506.             ActiveGad->Flags &= ~GFLG_SELECTED;
  3507.             // Add it back.
  3508.             if (AddGadget((struct Window *) ActiveGad->UserData, ActiveGad, activepos) == -1)
  3509.                 SetLastErr("RadioButtonClick failed to replace the old active gadget.");
  3510.             else
  3511.                 RefreshGList(ActiveGad, (struct Window *) ActiveGad->UserData, NULL, 1);
  3512.             }
  3513.         }
  3514.  
  3515.     // Activate the gadget clicked on
  3516.     rb->RBGad.Flags |= GFLG_SELECTED;
  3517.  
  3518.     // Add back the gadget clicked on.
  3519.     if (AddGadget((struct Window *) rb->RBGad.UserData, &(rb->RBGad), position) == -1)
  3520.         SetLastErr("RadioButtonClick failed to replace the new active gadget.");
  3521.     else
  3522.         {
  3523.         DrawRBCentre(rb);
  3524.         RefreshGList(&(rb->RBGad), (struct Window *) rb->RBGad.UserData, NULL, 1);
  3525.         }
  3526.  
  3527.     if (rb->Callfn)
  3528.         {
  3529.         Action = ACTION_RADIO_BUT;
  3530.         ActionPtr = rb;
  3531.         Gui.Done = TRUE;
  3532.         }
  3533.     }
  3534.  
  3535. static void AutRepButtonPress(PushButton *ButtPtr, GuiWindow *winptr)
  3536.    {
  3537.     int Special = 0;
  3538.  
  3539.    if (ButtPtr || Special)
  3540.       {
  3541.       struct IntuiMessage *ReleaseMessage;
  3542.       BOOL First = TRUE;
  3543.       do
  3544.          {
  3545.             if (ButtPtr->Active)
  3546.             {
  3547.             int tmp;
  3548.             if (ButtPtr->Callfn)
  3549.                tmp = (*(ButtPtr->Callfn))(ButtPtr);
  3550.                 Gui.Done = TRUE;
  3551.             }
  3552.          ReleaseMessage = (struct IntuiMessage *) GetMsg(winptr->Win->UserPort);
  3553.          if (ReleaseMessage)
  3554.             {
  3555.             if (!(ReleaseMessage->Class == GADGETUP || (ReleaseMessage->Class == MOUSEBUTTONS && ReleaseMessage->Code ==
  3556.                SELECTUP)))
  3557.                {
  3558.                ReplyMsg((struct Message *) ReleaseMessage);
  3559.                ReleaseMessage = NULL;
  3560.                }
  3561.             }
  3562.          if (!ReleaseMessage)
  3563.             {
  3564.             if (First)
  3565.                {
  3566.                ReleaseMessage = pause(Gui.ARdelay, winptr);
  3567.                First = FALSE;
  3568.                }
  3569.             else
  3570.                ReleaseMessage = pause(Gui.ARperiod, winptr);
  3571.             }
  3572.          } while (!ReleaseMessage);
  3573.       ReplyMsg((struct Message *) ReleaseMessage);
  3574.       }
  3575.    }
  3576.  
  3577. static BOOL ListBoxExists(ListBox *lb)
  3578.     {
  3579.     ListBox *li = Gui.FirstListBox;
  3580.     while (li)
  3581.         {
  3582.         if (li == lb)
  3583.             return TRUE;
  3584.         li = li->NextListBox;
  3585.         }
  3586.     return FALSE;
  3587.     }
  3588.  
  3589. static ListBox *CheckListBox(int x, int y, GuiWindow *winptr)
  3590.     {
  3591.     Diagnostic("CheckListBox", ENTER, TRUE);
  3592.     if (winptr)
  3593.         {
  3594.         ListBox *FindIt = Gui.FirstListBox;
  3595.         while (FindIt)
  3596.             if (FindIt->Win == winptr && x >= FindIt->WidgetData->left && x <= FindIt->WidgetData->left + FindIt->points[12] &&
  3597.                         y >= FindIt->WidgetData->top && y <= FindIt->WidgetData->top + FindIt->points[5] + (FindIt->NoTitles ?
  3598.                         (FindIt->NoTitles * FindIt->Font->ta_YSize) + (2 * FindIt->TBorder) + 3 : 0) &&
  3599.                         FindIt->Enabled && FindIt->hidden == 0)
  3600.                 break;
  3601.             else
  3602.                 FindIt = FindIt->NextListBox;
  3603.         return FindIt;
  3604.         }
  3605.     Diagnostic("CheckListBox", EXIT, TRUE);
  3606.     return NULL;
  3607.     }
  3608.  
  3609. static BOOL DDListBoxSelect(struct IntuiMessage *WinMsg, GuiWindow *winptr)
  3610.    {
  3611.    int y = WinMsg->MouseY, x = WinMsg->MouseX;
  3612.     BOOL Done = FALSE;
  3613.     struct EditBoxStruct *np = Gui.FirstEditBox;
  3614.     Diagnostic("DDListBoxSelect", ENTER, TRUE);
  3615.    while (np)
  3616.       {
  3617.       if (y > np->WidgetData->top && y < np->WidgetData->top + 9 && (GuiWindow *) np->editbox.UserData == winptr && np->enabled &&
  3618.              x > np->WidgetData->left + np->WidgetData->width && x < np->WidgetData->left + np->WidgetData->width + DD_LIST_BOX_BUTTON_WIDTH && np->list &&
  3619.                 np->hidden == 0 && !(np->list->Parent))
  3620.          {
  3621.             if (editptr && editptr->list && editptr->list->win && editptr->list->nlb)
  3622.                 {
  3623.                 BOOL SameOne = (editptr == np);
  3624.                 editptr = NewDDListBoxItemSelect(SameOne || nlbHiChild(editptr->list), NULL);
  3625.                 if (!(editptr || SameOne))
  3626.                     DropList(np);
  3627.                 }
  3628.             else
  3629.                 {
  3630.                 if (editptr || (lastactiveDDListBox && lastactiveDDListBox != np))
  3631.                     endedit();
  3632.                 if (!(editptr || (lastactiveDDListBox && lastactiveDDListBox != np)))
  3633.                     DropList(np);
  3634.                 }
  3635.          np = NULL;
  3636.             Done = TRUE;
  3637.          }
  3638.       else
  3639.          np = np->next;
  3640.       }
  3641.     Diagnostic("DDListBoxSelect", EXIT, TRUE);
  3642.     return Done;
  3643.    }
  3644.  
  3645. static struct ListElement *FindListBoxItem(char Key, DDListBox *listbox)
  3646.     {
  3647.     // Search for a list element starting with the character typed.
  3648.     struct ListElement *e, *start = listbox->list->first;
  3649.  
  3650.     // The list box contains no items.
  3651.     if (!start)
  3652.         return NULL;
  3653.  
  3654.     // Find the element to start at.  If no element is currently selected
  3655.     // then start at the first one.  Otherwise, start at the item after the
  3656.     // selected one (if the selected one is still in the list).
  3657.     if (strcmp(listbox->buffer, ""))
  3658.         {
  3659.         e = start;
  3660.         while (strcmp(e->string, listbox->buffer))
  3661.             {
  3662.             e = e->Next;
  3663.             if (!e)
  3664.                 break;
  3665.             }
  3666.         if (e)
  3667.             start = e->Next;
  3668.         if (!start)
  3669.             start = listbox->list->first;
  3670.         }
  3671.  
  3672.     // Now we know where to start, start looking for an element starting
  3673.     // with the typed character.
  3674.     e = start;
  3675.     while (toupper(e->string[0]) != toupper(Key))
  3676.         {
  3677.         e = e->Next;
  3678.         if (!e)
  3679.             e = listbox->list->first;
  3680.         if (e == start)
  3681.             return NULL;
  3682.         }
  3683.     return e;
  3684.     }
  3685.  
  3686. static void UpdateTimers(void)
  3687.     {
  3688.     Timer *t = Gui.FirstTimer;
  3689.  
  3690.     while (t && (Stop & GUI_CONTINUE))
  3691.         {
  3692.         if (t->running)
  3693.             {
  3694.             t->timesecs = time(NULL);
  3695.             if (t->Callfn && ((t->timesecs > t->lasttrigger && (t->WidgetData->flags & TM_SECOND)) ||
  3696.                                     (t->timesecs > t->lasttrigger + 59 && (t->WidgetData->flags & TM_MINUTE))))
  3697.                 {
  3698.                 t->lasttrigger = t->timesecs;
  3699.                 Stop = (*(t->Callfn))(t, t->timesecs - t->starttimesecs);
  3700.                 }
  3701.             }
  3702.         t = t->NextTimer;
  3703.         }
  3704.     }
  3705.  
  3706. RadioButton *FindRadioButtonByMsg(struct IntuiMessage *WinMsg)
  3707.     {
  3708.     RadioButton *rb = Gui.FirstRadioButton, *RetVal = NULL;
  3709.     while (rb)
  3710.         {
  3711.         if (&(rb->RBGad) == (struct Gadget *) WinMsg->IAddress)
  3712.             {
  3713.             RetVal = rb;
  3714.             break;
  3715.             }
  3716.         rb = rb->Next;
  3717.         }
  3718.     return RetVal;
  3719.     }
  3720.  
  3721. // Moves any necessary gadgets after a window has been re-sized.
  3722. void UpdateGadgets(GuiWindow *winptr)
  3723.     {
  3724.     BOOL ForSubList;
  3725.     UWORD GadPos;
  3726.     EditBox *eb = Gui.FirstEditBox;
  3727.     OutputBox *ob = Gui.FirstOutputBox;
  3728.     PushButton *pb = Gui.GGLfirst;
  3729.     TickBox *tb = Gui.FirstTickBox;
  3730.     RadioButton *rb = Gui.FirstRadioButton;
  3731.     ProgressBar *pi = Gui.FirstProgressBar;
  3732.     Frame *fr = Gui.FirstFrame;
  3733.     ListBox *lb = Gui.FirstListBox;
  3734.     register double HeightFactor = winptr->Win->Height / (double) winptr->NewWin.Height;
  3735.     register double WidthFactor = winptr->Win->Width / (double) winptr->NewWin.Width;
  3736.  
  3737.     while (tb)
  3738.         {
  3739.         if ((struct Window *) tb->TickBoxGad.UserData == winptr->Win && (tb->WidgetData->flags & S_AUTO_SIZE))
  3740.             { // We've found a tick box that needs moving.
  3741.             if (tb->hidden == 0)
  3742.                 GadPos = RemoveGList(winptr->Win, &tb->TickBoxGad, 1L);
  3743.             if (tb->hidden != 0 || GadPos != -1)
  3744.                 {
  3745.                 ResizeTickBox(tb, (int) (tb->WidgetData->os->left * WidthFactor), (int) (tb->WidgetData->os->top * HeightFactor), (int) (tb->WidgetData->os->width * WidthFactor), (int) (tb->WidgetData->os->height * HeightFactor), tb->hidden == 0);
  3746.                 if (tb->hidden == 0)
  3747.                     AddGList(winptr->Win, &tb->TickBoxGad, (unsigned long) GadPos, 1L, NULL);
  3748.                 }
  3749.             }
  3750.         tb = tb->Next;
  3751.         }
  3752.  
  3753.     while (rb)
  3754.         {
  3755.         if ((struct Window *) rb->RBGad.UserData == winptr->Win && (rb->WidgetData->flags & S_AUTO_SIZE))
  3756.             { // We've found a radio button that needs moving.
  3757.             if (rb->hidden == 0)
  3758.                 GadPos = RemoveGList(winptr->Win, &rb->RBGad, 1L);
  3759.             if (rb->hidden != 0 || GadPos != -1)
  3760.                 {
  3761.                 ResizeRadioButton(rb, (int) (rb->WidgetData->os->left * WidthFactor), (int) (rb->WidgetData->os->top * HeightFactor), (int) (rb->WidgetData->os->width * WidthFactor), (int) (rb->WidgetData->os->height * HeightFactor), rb->hidden == 0);
  3762.                 if (rb->hidden == 0)
  3763.                     AddGList(winptr->Win, &rb->RBGad, (unsigned long) GadPos, 1L, NULL);
  3764.                 }
  3765.             }
  3766.         rb = rb->Next;
  3767.         }
  3768.  
  3769.     while (ob)
  3770.         {
  3771.         if (ob->win == winptr && (ob->WidgetData->flags & S_AUTO_SIZE))
  3772.             // We've found an output box that needs moving.
  3773.             ResizeOutputBox(ob, (int) (ob->WidgetData->os->left * WidthFactor), (int) (ob->WidgetData->os->top * HeightFactor), (int) (ob->WidgetData->os->width * WidthFactor), ob->hidden == 0);
  3774.         ob = ob->next;
  3775.         }
  3776.  
  3777.     while (eb)
  3778.         {
  3779.         ForSubList = FALSE;
  3780.         if (eb->list)
  3781.             if (eb->list->Parent) // It's a sub-list box.  These don't have gadgets and don't need moving!
  3782.                 ForSubList = TRUE;
  3783.         if ((GuiWindow *) eb->editbox.UserData == winptr && (eb->WidgetData->flags & S_AUTO_SIZE) && !ForSubList)
  3784.             { // We've found an edit box or drop-down list box that needs moving.
  3785.             double NewWidth;
  3786.  
  3787.             /*    On older Amigas, drop-down list boxes won't be in the gadget list so we needn't remove them
  3788.                 and we mustn't put them in the list afterwards! */
  3789.             if (eb->hidden != 0 || (eb->list && Gui.LibVersion < A3000))
  3790.                 GadPos = 0;
  3791.             else
  3792.                 GadPos = RemoveGList(winptr->Win, &eb->editbox, 1L); // returns -1 for failure.
  3793.             if (GadPos != -1)
  3794.                 {
  3795.                 /*    If this is a drop-down list box which is currently dropped then we'll need to move the
  3796.                     window. */
  3797.                 if (eb->list)
  3798.                     NewWidth = ((eb->WidgetData->os->width + DD_LIST_BOX_BUTTON_WIDTH) * WidthFactor) - DD_LIST_BOX_BUTTON_WIDTH;
  3799.                 else
  3800.                     NewWidth = eb->WidgetData->os->width * WidthFactor;
  3801.                 if (editptr == eb && eb->list && eb->list->win && !eb->list->PopupWidth)
  3802.                     {
  3803.                     /*    Work out how far the window has to move (we can't just use the factors because the
  3804.                         dd-list box is moving relative to the window but the dd-list box window is moving
  3805.                         relative to the screen). */
  3806.                     int dx = (eb->WidgetData->os->left * WidthFactor) - (double) eb->WidgetData->left;
  3807.                     int dy = (eb->WidgetData->os->top * HeightFactor) - (double) eb->WidgetData->top;
  3808.                     int dl = NewWidth - (double) eb->WidgetData->width;
  3809.  
  3810.                     MoveWindow(eb->list->win->Win, dx, dy);
  3811.                     Gui.DDListX = ((GuiWindow *) editptr->editbox.UserData)->Win->LeftEdge;
  3812.                     Gui.DDListY = ((GuiWindow *) editptr->editbox.UserData)->Win->TopEdge;
  3813.                     SizeWindow(eb->list->win->Win, dl, 0);
  3814.                     }
  3815.                 ResizeEditBox(eb, (int) (eb->WidgetData->os->left * WidthFactor), (int) (eb->WidgetData->os->top * HeightFactor), (int) NewWidth, eb->hidden == 0);
  3816.                 /*    Add it back into the gadget list even if we're on an old amiga and it shouldn't be in the
  3817.                     list. */
  3818.                 if (eb->hidden == 0)
  3819.                     AddGList(winptr->Win, &eb->editbox, (unsigned long) (GadPos == 0 ? ~0 : GadPos), 1L, NULL);
  3820.                 }
  3821.             }
  3822.         eb = eb->next;
  3823.         }
  3824.  
  3825.     while (fr)
  3826.         {
  3827.         if ((GuiWindow *) fr->button.UserData == winptr && (fr->WidgetData->flags & S_AUTO_SIZE))
  3828.             { // We've found a frame that needs moving.
  3829.             if (fr->hidden == 0)
  3830.                 GadPos = RemoveGList(winptr->Win, &fr->button, 1L);
  3831.             if (GadPos != -1 || fr->hidden != 0)
  3832.                 {
  3833.                 TabControl *tc = NULL;
  3834.                 double buttontop = fr->WidgetData->os->top * HeightFactor;
  3835.                 double buttonheight = fr->WidgetData->os->height * HeightFactor;
  3836.                 int ibuttonheight = (int) buttonheight;
  3837.                 int ibuttontop = (int) buttontop;
  3838.  
  3839.                 if (fr->WidgetData->ParentControl && (fr->WidgetData->flags & SYS_FM_ROUNDED) && ((TabControl *) fr->WidgetData->ParentControl)->WidgetData->ObjectType == TabControlObject)
  3840.                     {
  3841.                     /*    The frame is the button part of a tab control so when we resize it we need to ensure
  3842.                         that the bottom edge of the button still touches the top edge of the tab control. */
  3843.                     tc = (TabControl *) fr->WidgetData->ParentControl;
  3844.                     ibuttonheight = tc->FirstTab->frame->button.TopEdge - ibuttontop;
  3845.                     }
  3846.  
  3847.                 ResizeFrame(fr, (int) (fr->WidgetData->os->left * WidthFactor), ibuttontop, (int) (fr->WidgetData->os->width * WidthFactor), ibuttonheight, fr->hidden == 0);
  3848.                 if (tc && tc->SelectedTab->pb == fr)
  3849.                     {
  3850.                     // The frame is the selected tab of a tab control.
  3851.                     Tab *t = tc->SelectedTab;
  3852.  
  3853.                     if (t) // found the correct tab.
  3854.                         {
  3855.                         short width = fr->button.Width - (t->next == NULL ? 2 : 1);
  3856.                         tc->FramePoints[0] = fr->button.LeftEdge - t->frame->button.LeftEdge + 1;
  3857.                         tc->FramePoints[2] = tc->FramePoints[0] + width - 1;
  3858.                         }
  3859.                     }
  3860.                 else if (fr->dark.NextBorder)
  3861.                     {
  3862.                     /*    The frame has a custom border.  I'm sure the user would appreciate it if we were to
  3863.                         resize it.  Don't resize it if this frame is part of a tab control - it will be dealt
  3864.                         with at the same place as the button's custom border is resized below. */
  3865.                     if (!(fr->WidgetData->ParentControl && ((TabControl *) fr->WidgetData->ParentControl)->WidgetData->ObjectType == TabControlObject))
  3866.                         {
  3867.                         struct Border *cb = fr->dark.NextBorder;
  3868.                         int l;
  3869.  
  3870.                         for (l = 0; l < cb->Count; l++)
  3871.                             {
  3872.                             int x = 2 * l;
  3873.                             cb->XY[x] = fr->cbCopy[x] * WidthFactor;
  3874.                             cb->XY[x+1] = fr->cbCopy[x+1] * HeightFactor;
  3875.                             }
  3876.                         }
  3877.                     }
  3878.                 if (fr->hidden == 0)
  3879.                     AddGList(winptr->Win, &fr->button, (unsigned long) GadPos, 1L, NULL);
  3880.                 }
  3881.             }
  3882.         fr = fr->next;
  3883.         }
  3884.  
  3885.     while (pb)
  3886.         {
  3887.         if ((GuiWindow *) pb->button.UserData == winptr && (pb->WidgetData->flags & S_AUTO_SIZE))
  3888.             { // We've found a button that needs moving.
  3889.             if (pb->hidden == 0)
  3890.                 GadPos = RemoveGList(winptr->Win, &pb->button, 1L);
  3891.             if (pb->hidden != 0 || GadPos != -1)
  3892.                 {
  3893.                 /*    If the window has shrunk, this resize may trash the border so we need to refresh it
  3894.                     later */
  3895.                 ResizeButton(pb, (int) (pb->WidgetData->os->left * WidthFactor), (int) (pb->WidgetData->os->top * HeightFactor), (int) (pb->WidgetData->os->width * WidthFactor), (int) (pb->WidgetData->os->height * HeightFactor), pb->hidden == 0);
  3896.                 if (pb->dark.NextBorder)
  3897.                     {
  3898.                     /*    The button has a custom border.  I'm sure the user would appreciate it if we were to
  3899.                         resize it. */
  3900.                     struct Border *cb = pb->dark.NextBorder;
  3901.                     int l;
  3902.  
  3903.                     for (l = 0; l < cb->Count; l++)
  3904.                         {
  3905.                         int x = 2 * l;
  3906.                         cb->XY[x] = pb->cbCopy[x] * WidthFactor;
  3907.                         cb->XY[x+1] = pb->cbCopy[x+1] * HeightFactor;
  3908.                         }
  3909.                     }
  3910.                 if (pb->hidden == 0)
  3911.                     AddGList(winptr->Win, &pb->button, (unsigned long) GadPos, 1L, NULL);
  3912.                 }
  3913.             }
  3914.         pb = pb->Next;
  3915.         }
  3916.  
  3917.     while (pi)
  3918.         {
  3919.         if (pi->win == winptr && (pi->WidgetData->flags & S_AUTO_SIZE))
  3920.             // We've found a progress bar that needs moving.
  3921.             ResizeProgressBar(pi, (int) (pi->WidgetData->os->left * WidthFactor), (int) (pi->WidgetData->os->top * HeightFactor), (int) (pi->WidgetData->os->width * WidthFactor), (int) (pi->WidgetData->os->height * HeightFactor), pi->hidden == 0);
  3922.         pi = pi->Next;
  3923.         }
  3924.  
  3925.     while (lb)
  3926.         {
  3927.         if (lb->Win == winptr && (lb->WidgetData->flags & S_AUTO_SIZE))
  3928.             {
  3929.             ListBoxItem *lbi = lb->FirstTitle;
  3930.             // We've found a list box that needs moving.
  3931.             if (lb->itemlist)
  3932.                 UndrawTreeControl(lb);
  3933.             ResizeListBox(lb, (int) (lb->WidgetData->os->left * WidthFactor), (int) (lb->WidgetData->os->top * HeightFactor), (int) (lb->WidgetData->os->width * WidthFactor), (int) (lb->WidgetData->os->height * HeightFactor), WidthFactor, HeightFactor, TRUE);
  3934.             if (lb->TabStop)
  3935.                 {
  3936.                 int i = 0;
  3937.                 BOOL items = (lbi ? FALSE : TRUE); // Starting with titles or items
  3938.                 if (!lbi)
  3939.                     lbi = lb->FirstItem;
  3940.                 while (lbi)
  3941.                     {
  3942.                     int *j = lb->TabStop, *k = lb->WidgetData->os->TabStop;
  3943.                     for (; *j != 0; j = &j[1], k = &k[1])
  3944.                         if (lbi->LeftEdge == ListBoxLeftEdge(lb, j[0]))
  3945.                             lbi->LeftEdge = ListBoxLeftEdge(lb, (int) (((double) k[0]) * WidthFactor));
  3946.                     lbi = lbi->NextText;
  3947.                     if (lbi == NULL && !items)
  3948.                         {
  3949.                         items = TRUE;
  3950.                         lbi = lb->FirstItem;
  3951.                         }
  3952.                     }
  3953.                 while (lb->TabStop[i] != 0)
  3954.                     {
  3955.                     lb->TabStop[i] = lb->WidgetData->os->TabStop[i] * WidthFactor;
  3956.                     i++;
  3957.                     }
  3958.                 }
  3959.             }
  3960.         lb = lb->NextListBox;
  3961.         }
  3962.  
  3963.     /* Draw the backgrounds for filled frames (even if the frame isn't autosizing because it may have
  3964.         been draw over by something that is. */
  3965.     fr = Gui.FirstFrame;
  3966.     while (fr)
  3967.         {
  3968.         if ((GuiWindow *) fr->button.UserData == winptr && fr->hidden == 0)
  3969.             {
  3970.             if (!(fr->WidgetData->flags & BN_CLEAR))
  3971.                 AreaColFill(winptr->Win->RPort, fr->button.LeftEdge, fr->button.TopEdge, fr->points[8] + 1,
  3972.                         fr->points[1] + 1, fr->light.BackPen);
  3973.  
  3974.             if (fr->bitmap)
  3975.                 {
  3976.                 GuiBitMap *ngbm, *gbm = fr->bitmap;
  3977.  
  3978.                 fr->bitmap = NULL;
  3979.                 while (gbm)
  3980.                     {
  3981.                     ngbm = gbm->next;
  3982.                     if (gbm->obm)
  3983.                         {
  3984.                         AttachBitMapToControl(gbm->obm, fr, 0, 0, -1, -1, gbm->flags);
  3985.                         FreeGuiBitMap(gbm->obm);
  3986.                         }
  3987.                     else
  3988.                         AttachBitMapToControl(gbm, fr, 0, 0, -1, -1, BM_SCALE | (gbm->flags & BM_OVERLAY ? BM_OVERLAY : 0));
  3989.                     if (gbm->bmi)
  3990.                         GuiFree(gbm->bmi);
  3991.                     FreeGuiBitMap(gbm);
  3992.                     gbm = ngbm;
  3993.                     }
  3994.                 }
  3995.             }
  3996.         fr = fr->next;
  3997.         }
  3998.     // Draw button backgrounds for filled buttons.
  3999.     pb = Gui.GGLfirst;
  4000.     while (pb)
  4001.         {
  4002.         if ((GuiWindow *) pb->button.UserData == winptr && pb->hidden == 0)
  4003.             {
  4004.             if (!(pb->WidgetData->flags & BN_CLEAR))
  4005.                 AreaColFill(winptr->Win->RPort, pb->button.LeftEdge, pb->button.TopEdge, pb->button.Width,
  4006.                         pb->button.Height, pb->light.BackPen);
  4007.  
  4008.             if (pb->bitmap)
  4009.                 {
  4010.                 GuiBitMap *ngbm, *gbm = pb->bitmap;
  4011.  
  4012.                 pb->bitmap = NULL;
  4013.                 while (gbm)
  4014.                     {
  4015.                     ngbm = gbm->next;
  4016.                     if (gbm->obm)
  4017.                         {
  4018.                         AttachBitMapToControl(gbm->obm, pb, 0, 0, -1, -1, gbm->flags);
  4019.                         FreeGuiBitMap(gbm->obm);
  4020.                         }
  4021.                     else
  4022.                         AttachBitMapToControl(gbm, pb, 0, 0, -1, -1, BM_SCALE | (gbm->flags & BM_OVERLAY ? BM_OVERLAY : 0));
  4023.                     if (gbm->bmi)
  4024.                         GuiFree(gbm->bmi);
  4025.                     FreeGuiBitMap(gbm);
  4026.                     gbm = ngbm;
  4027.                     }
  4028.                 }
  4029.             }
  4030.         pb = pb->Next;
  4031.         }
  4032.     // Draw backgrounds for filled tick boxes.
  4033.     tb = Gui.FirstTickBox;
  4034.     while (tb)
  4035.         {
  4036.         if ((struct Window *) tb->TickBoxGad.UserData == winptr->Win && !(tb->WidgetData->flags & BN_CLEAR))
  4037.             AreaColFill(winptr->Win->RPort, tb->TickBoxGad.LeftEdge, tb->TickBoxGad.TopEdge,
  4038.                     tb->TickBoxGad.Width, tb->TickBoxGad.Height, tb->nsTick.FrontPen);
  4039.         tb = tb->Next;
  4040.         }
  4041.     // Draw the filled bits of currently selected radio buttons unless they are hidden.
  4042.     rb = Gui.FirstRadioButton;
  4043.     while (rb)
  4044.         {
  4045.         if ((struct Window *) rb->RBGad.UserData == winptr->Win && (rb->RBGad.Flags & GFLG_SELECTED) &&
  4046.                 GadInWinList(&rb->RBGad, (struct Window *) rb->RBGad.UserData))
  4047.             DrawRBCentre(rb);
  4048.         rb = rb->Next;
  4049.         }
  4050.     // Redraw progress bars.
  4051.     pi = Gui.FirstProgressBar;
  4052.     while (pi)
  4053.         {
  4054.         if (pi->win == winptr)
  4055.             SetProgress(pi, pi->iprogress);
  4056.         pi = pi->Next;
  4057.         }
  4058.     // Refresh all of the output boxes
  4059.     ob = Gui.FirstOutputBox;
  4060.     while (ob)
  4061.         {
  4062.         /*    Refresh all output boxes in the window even if they haven't moved.  Updating other gadgets
  4063.             may have trashed them. */
  4064.         if (ob->win == winptr && ob->hidden == 0)
  4065.             {
  4066.             PrintIText(ob->win->Win->RPort, &ob->IText, 0, 0);
  4067.             DrawBorder(ob->win->Win->RPort, &ob->lborder, 0, 0);
  4068.             }
  4069.         ob = ob->next;
  4070.         }
  4071.     // Refresh all list boxes in the window.
  4072.     lb = Gui.FirstListBox;
  4073.     while (lb)
  4074.         {
  4075.         if (lb->Win == winptr)
  4076.             if (lb->itemlist)
  4077.             {
  4078.                 DrawTreeControl(lb);
  4079.  
  4080.                 // Update the vertical scroller
  4081.                 if (lb->UD)
  4082.                 {
  4083.                     int top = 0, maxlen = 0, maxtop = 0;
  4084.                     unsigned short body, pot;
  4085.  
  4086.                     FindMaxSizes(lb->itemlist, &maxlen, &maxtop, &top);
  4087.                     FindScrollerValues((maxtop + lb->Font->ta_YSize) / lb->Font->ta_YSize, (lb->WidgetData->height - 4 - (2 * lb->TBorder) - (lb->LR ? SCROLL_BUTTON_HEIGHT : 0)) / lb->Font->ta_YSize, (0 - CalcItemTop(lb->itemlist)) / lb->Font->ta_YSize, 1, &body, &pot);
  4088.                     NewModifyProp(&lb->UD->ScrollGad, lb->Win->Win, NULL, AUTOKNOB | FREEVERT | PROPNEWLOOK, 0, pot, 0, body, 1);
  4089.                 }
  4090.             }
  4091.             else
  4092.                 ListBoxRefresh(lb);
  4093.  
  4094.         lb = lb->NextListBox;
  4095.         }
  4096.     // Refreshing a window's frame also refreshes all of the gadgets in the window.
  4097.     RefreshWindowFrame(winptr->Win);
  4098.  
  4099.     /* Now everything's been refreshed, if we're on an old Amiga, remove the list boxes from the
  4100.         gadget list again. */
  4101.     if (Gui.LibVersion < A3000)
  4102.         {
  4103.         eb = Gui.FirstEditBox;
  4104.         while (eb)
  4105.             {
  4106.             if (eb->list)
  4107.                 if (!(eb->list->Parent))
  4108.                     RemoveGList(winptr->Win, &eb->editbox, 1L);
  4109.             eb = eb->next;
  4110.             }
  4111.         }
  4112.     }
  4113.  
  4114. static void ReactivateLastEditBox(void)
  4115.     {
  4116.     if (editptr || (lastactiveDDListBox && Gui.LibVersion >= A3000))
  4117.         {
  4118.         EditBox *active = editptr ? editptr : lastactiveDDListBox;
  4119.         // We can only activate a gadget in the active window.
  4120.         ActivateWindow(((GuiWindow *) active->editbox.UserData)->Win);
  4121.         ActivateGadget(&active->editbox, ((GuiWindow *) active->editbox.UserData)->Win, NULL);
  4122.         }
  4123.     }
  4124.  
  4125. struct Window* FOXLIB IntuiWindow(REGA0 GuiWindow *gw)
  4126.     {
  4127.     if (gw && ISGUIWINDOW(gw))
  4128.         return gw->Win;
  4129.     return NULL;
  4130.     }
  4131.  
  4132. static BOOL IsUserGadget(struct IntuiMessage *WinMsg, GuiWindow *ModalWin)
  4133.     {
  4134.     struct Gadget *gad = WinMsg->IAddress;
  4135.     UserGadget *ug = Gui.FirstUserGadget;
  4136.  
  4137.     while (ug)
  4138.         {
  4139.         if (ug->gad == gad)
  4140.             {
  4141.             if (ug->win)
  4142.                 {
  4143.                 if (ug->win->Sleep)
  4144.                     return TRUE;
  4145.                 if (ModalWin && ug->win != ModalWin)
  4146.                     return TRUE;
  4147.                 }
  4148.             Stop = (*(ug->fn))(gad, WinMsg);
  4149.             Gui.Done = TRUE;
  4150.             return TRUE;
  4151.             }
  4152.         ug = ug->next;
  4153.         }
  4154.     return FALSE;
  4155.     }
  4156.  
  4157. void CheckListBoxKeyPress(void)
  4158.     {
  4159.     if (ListBoxKeyPress != 0)
  4160.         {
  4161.         // User pressed a key while in a list box.
  4162.         if (lastactiveDDListBox && !lastactiveDDListBox->list->win)
  4163.             if (ListBoxKeyPress == ' ')
  4164.                 DropList(lastactiveDDListBox);
  4165.             else
  4166.                 {
  4167.                 struct ListElement *e = FindListBoxItem(ListBoxKeyPress, lastactiveDDListBox);
  4168.                 if (e)
  4169.                     {
  4170.                     NewTopBox = lastactiveDDListBox;
  4171.                     ListSelectAndActivate(FALSE, e);
  4172.                     }
  4173.                 }
  4174.         ListBoxKeyPress = 0;
  4175.         }
  4176.     }
  4177.  
  4178. TreeItem *FindItemByTop(TreeControl *tc, int top);
  4179.  
  4180. BOOL StartDragDrop(Frame *ObjPtr, GuiWindow *winptr, short MouseX, short MouseY)
  4181.     {
  4182.     BOOL retval = TRUE;
  4183.  
  4184.     if (ObjPtr->WidgetData->ObjectType == ListBoxObject || ObjPtr->WidgetData->ObjectType == TreeControlObjectType)
  4185.         {
  4186.         ListBox *ObjectPtr = (ListBox*) ObjPtr;
  4187.         TreeControl *tc = (TreeControl*) ObjPtr;
  4188.         int itemnum = 0;
  4189.         TreeItem *SelectedElem = NULL;
  4190.  
  4191.         if (ObjPtr->WidgetData->ObjectType == ListBoxObject)
  4192.             ListBoxItemFromXY(ObjectPtr, MouseX, MouseY, NULL, &itemnum);
  4193.         else
  4194.             SelectedElem = FindItemByTop(tc, MouseY - CalcItemTop(tc->itemlist) - tc->WidgetData->top - tc->TBorder - 1);
  4195.  
  4196.         if (SelectedElem || itemnum)
  4197.             {
  4198.             if (ObjectPtr->DragPointer)
  4199.                 SetPointer(winptr->Win, ObjectPtr->DragPointer,
  4200.                         (long) ObjectPtr->PointerHeight, (long) ObjectPtr->PointerWidth,
  4201.                         (long) ObjectPtr->PointerXOffset, (long) ObjectPtr->PointerYOffset);
  4202.             else
  4203.                 SetPointer(winptr->Win, ChipMemForDragPointer, 16L, 16L, -8L, -8L);
  4204.             if (ObjectPtr->Eventfn)
  4205.                 {
  4206.                 /* We're going to throw away the result of this function.  It's imperative
  4207.                     that this function doesn't close any windows, destroy any controls etc. */
  4208.                 if (ObjPtr->WidgetData->ObjectType == ListBoxObject)
  4209.                     (*(ObjectPtr->Eventfn))(ObjectPtr, LB_DRAG, itemnum, &ObjectPtr->DragData);
  4210.                 else
  4211.                     {
  4212.                     TCIntFnPtr tcfn = (TCIntFnPtr) tc->Eventfn;
  4213.                     (*(tcfn))(tc, LB_DRAG, SelectedElem, &tc->DragData);
  4214.                     }
  4215.                 }
  4216.             }
  4217.         else
  4218.             retval = FALSE;
  4219.         }
  4220.     else if (ObjPtr->WidgetData->ObjectType == FrameObject)
  4221.         {
  4222.         Frame *ObjectPtr = (Frame*) ObjPtr;
  4223.  
  4224.         if (ObjectPtr->DragPointer)
  4225.             SetPointer(winptr->Win, ObjectPtr->DragPointer,
  4226.                     (long) ObjectPtr->PointerHeight, (long) ObjectPtr->PointerWidth,
  4227.                     (long) ObjectPtr->PointerXOffset, (long) ObjectPtr->PointerYOffset);
  4228.         else
  4229.             SetPointer(winptr->Win, ChipMemForDragPointer, 16L, 16L, -8L, -8L);
  4230.         if (ObjectPtr->Callfn)
  4231.             {
  4232.             /* We're going to throw away the result of this function.  It's imperative
  4233.                 that this function doesn't close any windows, destroy any controls etc. */
  4234.             (*(ObjectPtr->Callfn))(ObjectPtr, FM_DRAG, MouseX - ObjectPtr->button.LeftEdge,
  4235.                     MouseY - ObjectPtr->button.TopEdge, &ObjectPtr->DragData);
  4236.             }
  4237.         if (ObjectPtr->WidgetData->flags & FM_DRAGOUTLINE)
  4238.             DrawDragOutline(ObjectPtr, winptr, FALSE, TRUE, 0, 0);
  4239.         }
  4240.     return retval;
  4241.     }
  4242.  
  4243. void **GetDropData(Frame *ObjPtr)
  4244.     {
  4245.     if (ObjPtr->WidgetData->ObjectType == ListBoxObject || ObjPtr->WidgetData->ObjectType == TreeControlObjectType)
  4246.         {
  4247.         ListBox *ObjectPtr = (ListBox*) ObjPtr;
  4248.         return &ObjectPtr->DragData;
  4249.         }
  4250.     else if (ObjPtr->WidgetData->ObjectType == FrameObject)
  4251.         {
  4252.         Frame *ObjectPtr = (Frame*) ObjPtr;
  4253.         return &ObjectPtr->DragData;
  4254.         }
  4255.     return NULL;
  4256.     }
  4257.  
  4258. void DoScreenSignals(unsigned long Signals, BOOL reset)
  4259.     {
  4260.     // Find the screen that was signalled.
  4261.     unsigned long signal = 0;
  4262.     GuiScreen *scr = Gui.FirstScr;
  4263.  
  4264.     while (scr)
  4265.         {
  4266.         if (Signals & (1L << scr->LastWinSig))
  4267.             {
  4268.             signal = (1L << scr->LastWinSig);
  4269.             break;
  4270.             }
  4271.         scr = scr->NextScr;
  4272.         }
  4273.     if (scr)
  4274.         {
  4275.         Stop = (*(scr->LastWinFn))(scr);
  4276.         Gui.Done = TRUE;
  4277.         }
  4278.     else
  4279.         SetLastErr("Screen not found.");
  4280.     if (signal && reset)
  4281.         SetSignal(0L, signal); // Reset the signal.
  4282.     }
  4283.  
  4284. void DoConsoleSignals(unsigned long Signals, BOOL reset)
  4285.     {
  4286.     int lch;
  4287.     GuiWindow *winptr = FindWindowByConSignal(Signals);
  4288.     unsigned int SigRec = CheckForChars(Signals, &lch);
  4289.  
  4290.     if (SigRec && lch != -1)
  4291.         {
  4292.         unsigned char stream[2];
  4293.         stream[0] = lch;
  4294.         stream[1] = 0;
  4295.         ProcessKeys(stream, winptr, stModalWin);
  4296.         if (reset)
  4297.             SetSignal(0L, SigRec);
  4298.         }
  4299.     }
  4300.  
  4301. int Select(ListBox *lb, long x, long y, unsigned long seconds, unsigned long micros, Frame **FrameDownPtr);
  4302.  
  4303. #define WinToScreenX(gw,x)    ((x)+(gw->Win->LeftEdge))
  4304. #define WinToScreenY(gw,y)    ((y)+(gw->Win->TopEdge))
  4305.  
  4306. #define ScreenToWinX(gw,x) ((x)-(gw->Win->LeftEdge))
  4307. #define ScreenToWinY(gw,y) ((y)-(gw->Win->TopEdge))
  4308.  
  4309. #define WinToWinX(source,target,x) ScreenToWinX((target),WinToScreenX((source),(x)))
  4310. #define WinToWinY(source,target,y) ScreenToWinY((target),WinToScreenY((source),(y)))
  4311.  
  4312. void DoWindowSignals(unsigned long Signals, BOOL reset, ListBox **SelectedLB, Frame **FrameDragPtr,
  4313.             Frame **FrameDownPtr)
  4314.     {
  4315.     unsigned long SigRec;
  4316.     struct IntuiMessage *WinMsg;
  4317.     GuiWindow *winptr = FindWindowBySignal(Signals, &SigRec);
  4318.  
  4319.     while (SigRec && (WinMsg = (struct IntuiMessage *) GetMsg(winptr->Win->UserPort)))
  4320.         {
  4321.         if (!IsUserGadget(WinMsg, stModalWin))
  4322.             {
  4323.             if (reset)
  4324.                 SetSignal(0L, SigRec);
  4325.  
  4326.             switch (WinMsg->Class)
  4327.                 {
  4328.                 ListBox *lb;
  4329.                 unsigned short numchars;
  4330.  
  4331.                 case IDCMP_RAWKEY:
  4332.                     /* We can process key presses no-matter which window they're for as long as we
  4333.                         don't activate any buttons in a window other than the modal one (if there is
  4334.                         one). */
  4335.                     if (GetConvertedKeys(WinMsg, &numchars))
  4336.                         {
  4337.                         unsigned char *stream = (unsigned char*) GuiMalloc((numchars+1)*sizeof(unsigned char), MEMF_CLEAR);
  4338.                         if (stream)
  4339.                             {
  4340.                             // RKCbuffer isn't terminated so we need to make a terminated copy.
  4341.                             strncpy((char*) stream, (char*) RKCbuffer, numchars);
  4342.                             ProcessKeys(stream, winptr, stModalWin);
  4343.                             GuiFree(stream);
  4344.                             }
  4345.                         }
  4346.                     break;
  4347.                 case GADGETUP :
  4348.                     /*    If a modal window is open then only process the message if it is for the modal
  4349.                         window */
  4350.                     if (winptr == stModalWin || !stModalWin)
  4351.                         {
  4352.                         EditBox *eb;
  4353.  
  4354.                         if (Action == ACTION_DRAG_BAR)
  4355.                             {
  4356.                             ListBox *lb = *SelectedLB;
  4357.                             /*    The user has just released a drag-bar.  If there was an edit box active
  4358.                                 when they started dragging the bar we should reset it now. */
  4359.                             Action = 0;
  4360.                             *SelectedLB = NULL;
  4361.                             ReactivateLastEditBox();
  4362.  
  4363.                             /* Now, if the user has just released the drag-bar of a list box which has the
  4364.                                 LB_CURSOR flag set and during the drag, the hilighted item changed then
  4365.                                 we should call the users event function now. */
  4366.                             if (lb)
  4367.                                 if (lb->WidgetData->flags & LB_CURSOR)
  4368.                                     if (lb->itemlist) // it's a tree control
  4369.                                         {
  4370.                                         if (SelectedLBHiItem != (ListBoxItem *) lb->hiitem)
  4371.                                             {
  4372.                                             Stop = ((TCIntFnPtr) *(lb->Eventfn))(lb, TC_CURSOR, lb->hiitem, NULL);
  4373.                                             Gui.Done = TRUE;
  4374.                                             }
  4375.                                         }
  4376.                                     else if (SelectedLBHiItem != lb->HiItem)
  4377.                                         {
  4378.                                         Stop = (*(lb->Eventfn))(lb, LB_CURSOR, lb->HiNum, NULL);
  4379.                                         Gui.Done = TRUE;
  4380.                                         }
  4381.                             }
  4382.                         else if (!(eb = FindEditBoxByWin(WinMsg)))
  4383.                             {
  4384.                             if (!NormalButtonFramePress(WinMsg, FrameDragPtr, FrameDownPtr))
  4385.                                 if (!ListScroll(WinMsg, winptr, SelectedLB))
  4386.                                     CheckTickBox(WinMsg);
  4387.                             }
  4388.                         else if (WinMsg->Code == 0) // (0 = return/enter)
  4389.                             {
  4390.                             // Return or enter pressed in an edit box.
  4391.                             Action = ACTION_EB_RETURN;
  4392.                             ActionPtr = eb;
  4393.                             Gui.Done = TRUE;
  4394.                             }
  4395.                         }
  4396.                     break;
  4397.                 case GADGETDOWN :
  4398.                     /*    If a modal window is open then only process the message if it is for the modal
  4399.                         window */
  4400.                     if (winptr == stModalWin || !stModalWin)
  4401.                         {
  4402.                         RadioButton *rb;
  4403.                         PushButton *pb;
  4404.                         lb = ListBoxScrollGad(WinMsg);
  4405.                         /*    If the user has selected a list box's scroll gadget then make a note of which one
  4406.                             and the currently hilighted item for when the user scrolls or releases it. */
  4407.                         if (lb)
  4408.                             {
  4409.                             *SelectedLB = lb;
  4410.                             SelectedLBHiItem = (lb->itemlist ? (ListBoxItem *) lb->hiitem : lb->HiItem);
  4411.                             }
  4412.                         if (!EditBoxSelected(WinMsg))
  4413.                             {
  4414.                             Frame *fr;
  4415.  
  4416.                             if (pb = FindButtonByMsg(WinMsg))
  4417.                                 AutRepButtonPress(pb, winptr);
  4418.                             else if (rb = FindRadioButtonByMsg(WinMsg))
  4419.                                 RadioButtonClick(rb);
  4420.                             else if (fr = FindFrameByMsg(WinMsg))
  4421.                                 if ((fr->WidgetData->flags & FM_DRAG) && fr->Active)
  4422.                                     {
  4423.                                     *FrameDownPtr = fr;
  4424.                                     ActionX = WinMsg->MouseX;
  4425.                                     ActionY = WinMsg->MouseY;
  4426.                                     }
  4427.                             }
  4428. //                        else
  4429. //                            DisplayMessage(WinMsg);
  4430.                         }
  4431.                     else
  4432.                         {
  4433.                         EditBox *ebp = FindEditBoxByWin(WinMsg);
  4434.                         /*    If there is a modal window open and the user clicks in an editbox in a
  4435.                             different window then deactivate the editbox immediately in order to prevent
  4436.                             the user editing it.  We can use a simple call to DeActivateStrGad() rather
  4437.                             than the more complex DeactivateUnknownEditBox() because the string gadget is
  4438.                             not in the modal window so the resulting GadgetUp will be ignored anyway. */
  4439.                         if (ebp)
  4440.                             DeActivateStrGad();
  4441.                         }
  4442.                     break;
  4443.                 case MENUPICK :
  4444.                     /*    If a modal window is open then only process the message if it is for the modal
  4445.                         window */
  4446.                     if (winptr == stModalWin || !stModalWin)
  4447.                         {
  4448.                         Frame *frame;
  4449.                         MenuNum = WinMsg->Code;
  4450.  
  4451.                         if (MenuNum == MENUNULL && ((frame = FrameRClick(winptr, WinMsg)) != NULL))
  4452.                             {
  4453.                             if (editptr || lastactiveDDListBox)
  4454.                                 endedit();
  4455.                             if (!(editptr || lastactiveDDListBox))
  4456.                                 {
  4457.                                 GuiWindow *w = GetWindow(frame);
  4458.                                 Action = ACTION_FRAME_RBUT;
  4459.                                 /* The window containing the frame that was clicked on may not be the active
  4460.                                     one when it is a right button click! */
  4461.                                 if (w == winptr)
  4462.                                     {
  4463.                                     ActionX = WinMsg->MouseX;
  4464.                                     ActionY = WinMsg->MouseY;
  4465.                                     }
  4466.                                 else
  4467.                                     {
  4468.                                     ActionX = WinMsg->MouseX + winptr->Win->LeftEdge - w->Win->LeftEdge;
  4469.                                     ActionY = WinMsg->MouseY + winptr->Win->TopEdge - w->Win->TopEdge;
  4470.                                     }
  4471.                                 ActionPtr = frame;
  4472.                                 Gui.Done = TRUE;
  4473.                                 }
  4474.                             }
  4475.                         else
  4476.                             {
  4477.                             MenuWinPtr = winptr;
  4478.                             Gui.Done = TRUE;
  4479.                             }
  4480.                         }
  4481.                     break;
  4482.                 case MOUSEBUTTONS :
  4483.                     /*    If a modal window is open then only process the message if it is for the modal
  4484.                         window */
  4485.                     if (winptr == stModalWin || !stModalWin)
  4486.                         {
  4487.                         if (WinMsg->Code == SELECTDOWN)
  4488.                             {
  4489.                             ListBox *FindIt = NULL;
  4490.                             if (!DDListBoxSelect(WinMsg, winptr))
  4491.                                 if (FindIt = CheckListBox(WinMsg->MouseX, WinMsg->MouseY, winptr))
  4492.                                     {
  4493.                                     /* If this is the list box in a drop-down list boxes window then we want to
  4494.                                         perform the function now - since that function was specified by FoxGui we
  4495.                                         know it won't do any harm! */
  4496.                                     if (editptr && editptr->list && editptr->list->nlb == FindIt)
  4497.                                         Stop = Select(FindIt, (long) WinMsg->MouseX, (long) WinMsg->MouseY, WinMsg->Seconds, WinMsg->Micros, FrameDownPtr);
  4498.                                     else
  4499.                                         {
  4500.                                         Gui.Done = TRUE;
  4501.                                         Action = ACTION_LIST_BOX;
  4502.                                         ActionPtr = FindIt;
  4503.                                         ActionWin = winptr;
  4504.                                         ActionX = WinMsg->MouseX;
  4505.                                         ActionY = WinMsg->MouseY;
  4506.                                         GuiSecs = WinMsg->Seconds;
  4507.                                         GuiMicros = WinMsg->Micros;
  4508.                                         }
  4509.                                     }
  4510.                             }
  4511.                         else if (WinMsg->Code == SELECTUP && *FrameDragPtr)
  4512.                             {
  4513.                             Action = ACTION_DROP;
  4514.                             ActionPtr = *FrameDragPtr;
  4515.                             ActionX = WinMsg->MouseX;
  4516.                             ActionY = WinMsg->MouseY;
  4517.                             if ((*FrameDragPtr)->WidgetData->flags & FM_DRAGOUTLINE)
  4518.                                 DrawDragOutline(*FrameDragPtr, winptr, TRUE,  FALSE, 0, 0);
  4519.                             *FrameDragPtr = NULL;
  4520.                             Gui.Done = TRUE;
  4521.                             }
  4522.                         /*
  4523.                         If the user has just dropped a list box,    that
  4524.                         SELECTDOWN will be followed by a SELECTUP here which
  4525.                         we need to filter out in order to prevent
  4526.                         EditBoxSelected from resetting editptr
  4527.                         */
  4528.                         else if (WinMsg->Code == SELECTUP && !(editptr && editptr->list))
  4529.                         {
  4530.                             Action = ACTION_EB_CLICK_OUT;
  4531.                             ActionPtr = WinMsg->IAddress;
  4532.                             Gui.Done = TRUE;
  4533.                         }
  4534.                         if (WinMsg->Code == SELECTUP)
  4535.                             *FrameDownPtr = NULL;
  4536.                         }
  4537.                     break;
  4538.                 case IDCMP_CLOSEWINDOW:
  4539.                     if (winptr == stModalWin || !stModalWin)
  4540.                         {
  4541.                         if (editptr || lastactiveDDListBox)
  4542.                             endedit();
  4543.                         if (!(editptr || lastactiveDDListBox))
  4544.                             {
  4545.                             Action = ACTION_CLOSE;
  4546.                             ActionPtr = winptr;
  4547.                             Gui.Done = TRUE;
  4548.                             }
  4549.                         }
  4550.                     break;
  4551.                 case IDCMP_NEWSIZE:
  4552.                     // The user has re-sized a window.  We may have to move some gadgets.
  4553.                     Action = ACTION_RESIZE;
  4554.                     ActionPtr = winptr;
  4555.                     Gui.Done = TRUE;
  4556.                     break;
  4557.                 case IDCMP_DISKINSERTED:
  4558.                     if (winptr->EventFn)
  4559.                     {
  4560.                         // The user has inserted a disk.
  4561.                         Action = ACTION_DISKIN;
  4562.                         ActionPtr = winptr;
  4563.                         Gui.Done = TRUE;
  4564.                     }
  4565.                     break;
  4566.                 case IDCMP_DISKREMOVED:
  4567.                     if (winptr->EventFn)
  4568.                     {
  4569.                         // The user has removed a disk.
  4570.                         Action = ACTION_DISKOUT;
  4571.                         ActionPtr = winptr;
  4572.                         Gui.Done = TRUE;
  4573.                     }
  4574.                     break;
  4575.                 case IDCMP_ACTIVEWINDOW:
  4576.                     if (winptr->EventFn)
  4577.                     {
  4578.                         Action = ACTION_WINDOW_ACTIVE;
  4579.                         ActionPtr = winptr;
  4580.                         Gui.Done = TRUE;
  4581.                     }
  4582.                     break;
  4583.                 case IDCMP_MOUSEMOVE:
  4584.                     /*    If a modal window is open then only process the message if it is for the modal
  4585.                         window */
  4586.                     if (winptr == stModalWin || !stModalWin)
  4587.                         {
  4588.                         if (*SelectedLB)
  4589.                             {
  4590.                             /*    User is dragging a list box scroll bar so update the imagery.  This won't
  4591.                                 cause a change of focus to occur but it will cause Intuition to remove the
  4592.                                 cursor from the currently active edit box if there is one so we'll have to put
  4593.                                 it back afterwards.  We'll have to do that when the user releases the mouse
  4594.                                 button (i.e. on the gadget up event).  If we try to do it here, the scroll gadget
  4595.                                 will still be active and so it won't work. */
  4596.                             if ((*SelectedLB)->itemlist) // It's a tree control
  4597.                                 UpdateTCScrollGadImagery(*SelectedLB);
  4598.                             else
  4599.                                 UpdateLBScrollGadImagery(*SelectedLB);
  4600.                             // Make a note of the fact that the user is dragging a bar.
  4601.                             Action = ACTION_DRAG_BAR;
  4602.                             }
  4603.                         else if (*FrameDownPtr && (WinMsg->MouseX != ActionX || WinMsg->MouseY != ActionY) &&
  4604.                                 *FrameDragPtr != *FrameDownPtr)
  4605.                             {
  4606.                             // The user is dragging a drag-dropable object.
  4607.                             BOOL success = StartDragDrop(*FrameDownPtr, winptr, ActionX, ActionY);
  4608.                             if (success)
  4609.                                 *FrameDragPtr = *FrameDownPtr;
  4610.                             }
  4611.                         else if (*FrameDragPtr)
  4612.                             {
  4613.                             GuiWindow *wOver;
  4614.  
  4615.                             if ((*FrameDragPtr)->WidgetData->flags & FM_DRAGOUTLINE)
  4616.                                 DrawDragOutline(*FrameDragPtr, winptr, TRUE, TRUE, WinMsg->MouseX - ActionX,
  4617.                                     WinMsg->MouseY - ActionY);
  4618.  
  4619.                             wOver = FindDropWindow(winptr, WinMsg->MouseX, WinMsg->MouseY);
  4620.                             if (wOver)
  4621.                                 {
  4622.                                 ListBox *OverList;
  4623.  
  4624.                                 if ((OverList = FindDropList(wOver, WinToScreenX(winptr, WinMsg->MouseX),
  4625.                                         WinToScreenY(winptr, WinMsg->MouseY))) != NULL)
  4626.                                     { // Over a listbox.
  4627.                                     if (OverList->itemlist) // It's a Tree Control
  4628.                                         {
  4629.                                         TreeItem *ItemOver = FindItemByTop(OverList, WinMsg->MouseY -
  4630.                                                 CalcItemTop(OverList->itemlist) - OverList->WidgetData->top - OverList->TBorder - 1);
  4631.                                         if (ItemOver)
  4632.                                             {
  4633.                                             if (gDDLastTreeOver && gDDLastTreeOver != OverList)
  4634.                                                 {
  4635.                                                 ClearTreeControlDropNum(gDDLastTreeOver, gDDLastLeafOver);
  4636.                                                 gDDLastTreeOver = OverList;
  4637.                                                 gDDLastLeafOver = SetTreeControlDropNum(OverList, ItemOver, NULL);
  4638.                                                 }
  4639.                                             else
  4640.                                                 {
  4641.                                                 gDDLastTreeOver = OverList;
  4642.                                                 gDDLastLeafOver = SetTreeControlDropNum(OverList, ItemOver, gDDLastLeafOver);
  4643.                                                 }
  4644.                                             }
  4645.                                         }
  4646.                                     else
  4647.                                         {
  4648.                                         int lbi = -1;
  4649.                                         ListBoxItemFromXY(OverList, WinToWinX(winptr, wOver, WinMsg->MouseX),
  4650.                                                 WinToWinY(winptr, wOver, WinMsg->MouseY), NULL, &lbi);
  4651.  
  4652.  
  4653.                                         if (lbi != -1)
  4654.                                             {
  4655.                                             if (gDDLastListOver && gDDLastListOver != OverList)
  4656.                                                 {
  4657.                                                 ClearListBoxDropNum(gDDLastListOver, gDDLastItemOver);
  4658.                                                 gDDLastListOver = OverList;
  4659.                                                 gDDLastItemOver = SetListBoxDropNum(OverList, lbi, NULL);
  4660.                                                 }
  4661.                                             else
  4662.                                                 {
  4663.                                                 gDDLastListOver = OverList;
  4664.                                                 gDDLastItemOver = SetListBoxDropNum(OverList, lbi, gDDLastItemOver);
  4665.                                                 }
  4666.                                             }
  4667.                                         }
  4668.                                     }
  4669.                                 else
  4670.                                     {
  4671.                                     if (gDDLastListOver && gDDLastItemOver)
  4672.                                         {
  4673.                                         ClearListBoxDropNum(gDDLastListOver, gDDLastItemOver);
  4674.                                         gDDLastListOver = NULL;
  4675.                                         gDDLastItemOver = NULL;
  4676.                                         }
  4677.                                     if (gDDLastTreeOver && gDDLastLeafOver)
  4678.                                         {
  4679.                                         ClearTreeControlDropNum(gDDLastTreeOver, gDDLastLeafOver);
  4680.                                         gDDLastTreeOver = NULL;
  4681.                                         gDDLastLeafOver = NULL;
  4682.                                         }
  4683.                                     }
  4684.                                 }
  4685.                             }
  4686.                         }
  4687.                 default :
  4688.                         // Allow the user to move windows even if there is a modal one above.
  4689.                         if (editptr && editptr->list)
  4690.                             {
  4691.                             // If a drop-down list box is open, move the list.
  4692.                             int Dx = ((GuiWindow *) editptr->editbox.UserData)->Win->LeftEdge - Gui.DDListX;
  4693.                             int Dy = ((GuiWindow *) editptr->editbox.UserData)->Win->TopEdge - Gui.DDListY;
  4694.                             if ((Dx || Dy) && !(editptr->list->PopupWidth))
  4695.                                 {
  4696.                                 MoveWindow(editptr->list->win->Win, Dx, Dy);
  4697.                                 Gui.DDListX = ((GuiWindow *) editptr->editbox.UserData)->Win->LeftEdge;
  4698.                                 Gui.DDListY = ((GuiWindow *) editptr->editbox.UserData)->Win->TopEdge;
  4699.                                 }
  4700.                             }
  4701.  
  4702.                     // The user may have just dragged this window across the screen.  Let's check.
  4703.                     if ((winptr->NewWin.LeftEdge != winptr->Win->LeftEdge || winptr->NewWin.TopEdge !=
  4704.                             winptr->Win->TopEdge) && winptr->EventFn)
  4705.                         {
  4706.                         winptr->NewWin.LeftEdge = winptr->Win->LeftEdge;
  4707.                         winptr->NewWin.TopEdge = winptr->Win->TopEdge;
  4708.                         Action = ACTION_WINDOW_DRAG;
  4709.                         ActionPtr = winptr;
  4710.                         Gui.Done = TRUE;
  4711.                         }
  4712.                     break;
  4713.                 }
  4714.             ReplyMsg((struct Message *) WinMsg);
  4715.             }
  4716.         UpdateTimers();
  4717.         } // while GetMsg()
  4718.     if (NewDDListSelect)
  4719.         Stop = NewDDListBoxSelFn(NewDDListSelect);
  4720.     }
  4721.  
  4722. static Frame *FindDropFrame(GuiWindow *Target, int ScreenX, int ScreenY)
  4723.     {
  4724.     Frame *fr = Gui.FirstFrame;
  4725.     int x = ScreenX - Target->Win->LeftEdge;
  4726.     int y = ScreenY - Target->Win->TopEdge;
  4727.  
  4728.     while (fr)
  4729.         {
  4730.         if (GetWindow(fr) == Target)
  4731.             {
  4732.             BOOL rounded = ((fr->WidgetData->flags & SYS_FM_ROUNDED) && fr->points[1] + 1 >= 6 && !(fr->WidgetData->flags & FM_BORDERLESS));
  4733.             if (fr->Active && x >= fr->button.LeftEdge && x <= fr->button.LeftEdge + (rounded ?
  4734.                     fr->points[24] : fr->points[8]) && y >= fr->button.TopEdge && y <= fr->button.TopEdge +
  4735.                     fr->points[1] && (fr->WidgetData->flags & FM_DROP) && fr->hidden == 0)
  4736.                 {
  4737.                 fr = CheckForChildren(fr, x, y);
  4738.                 break;
  4739.                 }
  4740.             }
  4741.         fr = fr->next;
  4742.         }
  4743.     return fr;
  4744.     }
  4745.  
  4746. static ListBox *FindDropList(GuiWindow *Target, int ScreenX, int ScreenY)
  4747.     {
  4748.     ListBox *lb = Gui.FirstListBox;
  4749.     int x = ScreenX - Target->Win->LeftEdge;
  4750.     int y = ScreenY - Target->Win->TopEdge;
  4751.  
  4752.     while (lb)
  4753.         {
  4754.         if (GetWindow(lb) == Target)
  4755.             {
  4756.             if (x >= lb->WidgetData->left && x <= lb->WidgetData->left + lb->WidgetData->width && y >= lb->WidgetData->top && y <= lb->WidgetData->top + lb->WidgetData->height &&
  4757.                     (lb->WidgetData->flags & LB_DROP) && lb->hidden == 0)
  4758.                 break;
  4759.             }
  4760.         lb = lb->NextListBox;
  4761.         }
  4762.     return lb;
  4763.     }
  4764.  
  4765. static GuiWindow *FindDropWindow(GuiWindow *SourceWindow, short ActionX, short ActionY)
  4766.     {
  4767.     GuiWindow *DropWindow = NULL;
  4768.  
  4769.     if (SourceWindow)
  4770.         {
  4771.         struct Screen *sc = SourceWindow->Win->WScreen;
  4772.         if (sc)
  4773.             {
  4774.             struct Layer *la = WhichLayer(&(sc->LayerInfo), (long) ActionX + SourceWindow->Win->LeftEdge,
  4775.                     (long) ActionY + SourceWindow->Win->TopEdge);
  4776.             if (la)
  4777.                 {
  4778.                 DropWindow = Gui.GWLfirst;
  4779.                 while (DropWindow)
  4780.                     {
  4781.                     if (DropWindow->Win->WLayer == la)
  4782.                         break;
  4783.                     DropWindow = DropWindow->next;
  4784.                     }
  4785.                 }
  4786.             }
  4787.         }
  4788.     return DropWindow;
  4789.     }
  4790.  
  4791. extern int TCSelect(TreeControl *tc, long x, long y, unsigned long seconds, unsigned long micros, Frame **FrameDownPtr);
  4792.  
  4793. void DoActions(Frame **FrameDownPtr)
  4794.     {
  4795.     if (ActionPtr || MenuWinPtr)
  4796.         {
  4797.         GuiWindow *MWP = MenuWinPtr;
  4798.         void *AP = ActionPtr;
  4799.         ActionPtr = NULL; // Stop CheckMessages() from triggering this same function again.
  4800.         MenuWinPtr = NULL;
  4801.  
  4802.         if (AP)
  4803.             {
  4804.             switch (Action)
  4805.                 {
  4806.                 TickBox *tb;
  4807.                 RadioButton *rb;
  4808.                 PushButton *pb;
  4809.                 Frame *f;
  4810.                 GuiWindow *gw, *Target;
  4811.                 ListBox *lb;
  4812.                 EditBox *eb;
  4813.                 struct IntuiMessage im;
  4814.  
  4815.                 case ACTION_EB_CLICK_OUT:
  4816.                     im.IAddress = (struct Gadget*) ActionPtr;
  4817.                     EditBoxSelected(&im);
  4818.                     break;
  4819.  
  4820.                 case ACTION_EB_RETURN:
  4821.                     eb = (EditBox *) AP;
  4822.                     /*    The user has pressed return or enter, so call the validation function now
  4823.                         because there won't be a GADGETDOWN message to follow, BUT don't call the
  4824.                         validation function if the gadget up message isn't for the currently active
  4825.                         editbox (i.e. this gadget up may have been caused by a call to
  4826.                         SetEditBoxFocus or by a validation function returning FALSE after a tab). */
  4827.                     if (eb == editptr)
  4828.                         EditBoxSelected(NULL);
  4829.                     lastactiveDDListBox = editptr = NULL;
  4830.                     break;
  4831.  
  4832.                 case ACTION_DISKIN:
  4833.                     gw = (GuiWindow *) AP;
  4834.                     // We know the window has an EventFn because we checked before we set ActionPtr
  4835.                     Stop = (*(gw->EventFn))(gw, GW_DISKIN, 0, 0, NULL);
  4836.                     break;
  4837.                 case ACTION_DISKOUT:
  4838.                     gw = (GuiWindow *) AP;
  4839.                     // We know the window has an EventFn because we checked before we set ActionPtr
  4840.                     Stop = (*(gw->EventFn))(gw, GW_DISKOUT, 0, 0, NULL);
  4841.                     break;
  4842.                 case ACTION_WINDOW_ACTIVE:
  4843.                     gw = (GuiWindow *) AP;
  4844.                     // We know the window has an EventFn because we checked before we set ActionPtr
  4845.                     Stop = (*(gw->EventFn))(gw, GW_ACTIVE, 0, 0, NULL);
  4846.                     break;
  4847.                 case ACTION_WINDOW_DRAG:
  4848.                     gw = (GuiWindow *) AP;
  4849.                     // We know the window has an EventFn because we checked before we set ActionPtr
  4850.                     Stop = (*(gw->EventFn))(gw, GW_DRAG, gw->Win->LeftEdge, gw->Win->TopEdge, NULL);
  4851.                     break;
  4852.                 case ACTION_RESIZE:
  4853.                     gw = (GuiWindow *) AP;
  4854.                     UpdateGadgets(gw);
  4855.  
  4856.                     if (editptr || lastactiveDDListBox)
  4857.                         endedit();
  4858.                     if (gw->EventFn)
  4859.                         Stop = (*(gw->EventFn))(gw, GW_SIZE, gw->Win->Width, gw->Win->Height, NULL);
  4860.                     break;
  4861.                 case ACTION_LIST_BOX:
  4862.                     lb = (ListBox *) AP;
  4863.                     if (editptr || lastactiveDDListBox)
  4864.                         endedit();
  4865.                     /*    endedit() could cause destruction of the list box (depending on what the user has
  4866.                         in the event function) so let's check it still exists! */
  4867.                     if (ListBoxExists(lb) && !(editptr || lastactiveDDListBox))
  4868.                         {
  4869.                         if (lb->WidgetData->flags & LB_DRAG)
  4870.                             {
  4871.                             *FrameDownPtr = (Frame*) lb;
  4872.                             if (!(ActionWin->Win->Flags & WFLG_REPORTMOUSE))
  4873.                                 {
  4874.                                 Forbid();
  4875.                                 ActionWin->Win->Flags |= WFLG_REPORTMOUSE;
  4876.                                 Permit();
  4877.                                 DragWinFlagsChanged = TRUE;
  4878.                                 }
  4879.                             }
  4880.                         if (lb->itemlist) // It's a Tree Control really
  4881.                             Stop = TCSelect((TreeControl *) lb, (long) ActionX, (long) ActionY, GuiSecs, GuiMicros, FrameDownPtr);
  4882.                         else
  4883.                             Stop = Select(lb, (long) ActionX, (long) ActionY, GuiSecs, GuiMicros, FrameDownPtr);
  4884.                         }
  4885.                     break;
  4886.                 case ACTION_CLOSE:
  4887.                     gw = (GuiWindow *) AP;
  4888.                     if (gw->EventFn)
  4889.                         Stop = (*(gw->EventFn))(gw, GW_CLOSE, 0, 0, NULL);
  4890.                     if (!(Stop & GUI_CANCEL))
  4891.                         CloseGuiWindow(gw);
  4892.                     else
  4893.                         Stop = Stop - GUI_CANCEL;
  4894.                     break;
  4895.                 case ACTION_TICKBOX:
  4896.                     tb = (TickBox *) AP;
  4897.                     if (SetTickBoxValue(tb, !tb->Ticked))
  4898.                         if (tb->Callfn)
  4899.                          Stop = (*(tb->Callfn))(tb);
  4900.                     break;
  4901.                 case ACTION_BUTTON:
  4902.                     pb = (PushButton *) AP;
  4903.                     if (pb->Filefn)
  4904.                         {
  4905.                         SleepFile();
  4906.                         Stop = (*(pb->Filefn))(GetFName(), GetPath());
  4907.                         WakeFile();
  4908.                         }
  4909.                     else if (pb->Callfn)
  4910.                         Stop = (*(pb->Callfn))(pb);
  4911.                     break;
  4912.                 case ACTION_FRAME_LBUT:
  4913.                 case ACTION_FRAME_RBUT:
  4914.                     f = (Frame *) AP;
  4915.                     gw = GetWindow(f);
  4916.                     if (f->Callfn)
  4917.                         Stop = (*(f->Callfn))(f, Action == ACTION_FRAME_LBUT ? FM_LBUT : FM_RBUT, ActionX -
  4918.                                 f->button.LeftEdge, ActionY - f->button.TopEdge, NULL);
  4919.                     break;
  4920.                 case ACTION_RADIO_BUT:
  4921.                     rb = (RadioButton *) AP;
  4922.                     Stop = (*(rb->Callfn))(rb);
  4923.                     break;
  4924.                 case ACTION_DROP:
  4925.                     Target = NULL; /* Initialising this in the declarations above DOES NOT WORK!  Compiler
  4926.                                             bug? */
  4927.                     f = (Frame *) AP;
  4928.                     gw = GetWindow(f);
  4929.                     if (DragWinFlagsChanged)
  4930.                         {
  4931.                         Forbid();
  4932.                         gw->Win->Flags &= ~WFLG_REPORTMOUSE;
  4933.                         Permit();
  4934.                         DragWinFlagsChanged = FALSE;
  4935.                         }
  4936.                     Target = FindDropWindow(gw, ActionX, ActionY);
  4937.                     if (gw)
  4938.                         ClearPointer(gw->Win);
  4939.                     if (Target)
  4940.                         {
  4941.                         // Check whether the object was dropped onto another frame or a list box
  4942.                         ListBox *DropList;
  4943.                         Frame *dropFrame;
  4944.                         void **DropData = GetDropData(f);
  4945.  
  4946.                         if ((DropList = FindDropList(Target, WinToScreenX(gw, ActionX),
  4947.                                 WinToScreenY(gw, ActionY))) != NULL)
  4948.                             {    // It was dropped in a listbox.
  4949.                             if (gDDLastListOver && gDDLastItemOver)
  4950.                                 {
  4951.                                 ClearListBoxDropNum(gDDLastListOver, gDDLastItemOver);
  4952.                                 gDDLastListOver = NULL;
  4953.                                 gDDLastItemOver = NULL;
  4954.                                 }
  4955.                             if (gDDLastTreeOver && gDDLastLeafOver)
  4956.                                 {
  4957.                                 ClearTreeControlDropNum(gDDLastTreeOver, gDDLastLeafOver);
  4958.                                 gDDLastTreeOver = NULL;
  4959.                                 gDDLastLeafOver = NULL;
  4960.                                 }
  4961.                             if (DropList->Eventfn)
  4962.                                 if (DropList->itemlist) // It's a Tree Control
  4963.                                     {
  4964.                                     TreeItem *DroppedOver = FindItemByTop(DropList, ActionY -
  4965.                                             CalcItemTop(DropList->itemlist) - DropList->WidgetData->top - DropList->TBorder - 1);
  4966.                                     Stop = ((TCIntFnPtr) *(DropList->Eventfn))(DropList, TC_DROP, DroppedOver, DropData);
  4967.                                     }
  4968.                                 else
  4969.                                     {
  4970.                                     int lbi;
  4971.                                     ListBoxItemFromXY(DropList, WinToWinX(gw, Target, ActionX),
  4972.                                             WinToWinY(gw, Target, ActionY), NULL, &lbi);
  4973.                                     Stop = (*(DropList->Eventfn))(DropList, LB_DROP, lbi, DropData);
  4974.                                     }
  4975.                             }
  4976.                         else if ((dropFrame = FindDropFrame(Target, WinToScreenX(gw, ActionX),
  4977.                                 WinToScreenY(gw, ActionY))) != NULL)
  4978.                             {    // It was dropped in a frame.
  4979.                             if (dropFrame->Callfn)
  4980.                                 Stop = (*(dropFrame->Callfn))(dropFrame, FM_DROP, WinToWinX(gw, Target, ActionX)
  4981.                                         - dropFrame->button.LeftEdge, WinToWinY(gw, Target, ActionY)
  4982.                                         - dropFrame->button.TopEdge, DropData);
  4983.                             }
  4984.                         else // it was dropped in a window.
  4985.                             {
  4986.                             if ((Target->WidgetData->flags & GW_DROP) && Target->EventFn)
  4987.                                 Stop = (*(Target->EventFn))(Target, GW_DROP, WinToWinX(gw, Target, ActionX),
  4988.                                         WinToWinY(gw, Target, ActionY), *DropData);
  4989.                             }
  4990.                         }
  4991.                 default:
  4992.                     break;
  4993.                 }
  4994.             AP = NULL;
  4995.             Action = 0;
  4996.             }
  4997.         else
  4998.             { /* Process menu selections */
  4999.             struct MenuItem *item = NULL;
  5000.             if (MWP->FirstMenu && MWP->MenuFn)
  5001.                 if (MenuNum != MENUNULL)
  5002.                     {
  5003.                     if (editptr || lastactiveDDListBox)
  5004.                         endedit();
  5005.                     if (!(editptr || lastactiveDDListBox))
  5006.                         while (MenuNum != MENUNULL)
  5007.                             {
  5008.                             item = (struct MenuItem *) ItemAddress(MWP->FirstMenu, MenuNum);
  5009.                             MenuNum = item->NextSelect;
  5010.                             Stop = (*(MWP->MenuFn))(MWP, item);
  5011.                             }
  5012.                     }
  5013.             MWP = NULL;
  5014.             MenuNum = MENUNULL;
  5015.             if (!item)
  5016.                 if (editptr)
  5017.                     ActivateGadget(&editptr->editbox, ((GuiWindow *) editptr->editbox.UserData)->Win, NULL);
  5018.                 else if (lastactiveDDListBox)
  5019.                     ActivateGadget(&lastactiveDDListBox->editbox, ((GuiWindow *) lastactiveDDListBox->editbox.UserData)->Win, NULL);
  5020.             }
  5021.         }
  5022.     }
  5023.  
  5024. void FOXLIB CheckMessages(void)
  5025.     {
  5026.     GuiWindow *gwl;
  5027.     GuiScreen *gs;
  5028.     unsigned long WinSignals, ScrSignals, ConSignals, Signals;
  5029.     BOOL SomeSignals = TRUE;
  5030.     static ListBox *SelectedLB = NULL;
  5031.     static Frame *FrameDragPtr = NULL;
  5032.     static Frame *FrameDownPtr = NULL;
  5033.  
  5034.     /* If this doesn't work too well the alternative is to make SelectedLB non-static and change the line
  5035.         below to "while (SomeSignals || SelectedLB)" so that the loop won't end until the user stops
  5036.         dragging the scroll bar.  That may be a better way anyway!
  5037.         The same may also be true of FrameDragPtr & FrameDownPtr which point to a frame being dragged. */
  5038.     while (SomeSignals)
  5039.         {
  5040.         WinSignals = ScrSignals = ConSignals = 0L;
  5041.         SomeSignals = FALSE;
  5042.         gwl = Gui.GWLfirst;
  5043.         gs = Gui.FirstScr;
  5044.  
  5045.         // Create our signal masks
  5046.         while (gwl)
  5047.             {
  5048.             WinSignals |= gwl->WindowSig;
  5049.             ConSignals |= gwl->ConReadSig;
  5050.             gwl = gwl->next;
  5051.             }
  5052.         while (gs)
  5053.             {
  5054.             ScrSignals |= (1L << gs->LastWinSig);
  5055.             gs = gs->NextScr;
  5056.             }
  5057.  
  5058.         CheckListBoxKeyPress();
  5059.  
  5060.         // Check for signals
  5061.         Signals = SetSignal(0L, 0L);
  5062.  
  5063.         if (Signals & ScrSignals)
  5064.             {
  5065.             SomeSignals = TRUE;
  5066.             DoScreenSignals(Signals, TRUE);
  5067.             }
  5068.         if (Signals & ConSignals)
  5069.             {
  5070.             SomeSignals = TRUE;
  5071.             DoConsoleSignals(Signals, TRUE);
  5072.             }
  5073.         if (Signals & WinSignals)
  5074.             {
  5075.             SomeSignals = TRUE;
  5076.             DoWindowSignals(Signals, TRUE, &SelectedLB, &FrameDragPtr, &FrameDownPtr);
  5077.             }
  5078.         //    Maybe DoActions() should only be called if Gui.Done == TRUE ?
  5079.         DoActions(&FrameDownPtr);
  5080.         }
  5081.     }
  5082.  
  5083. void WinMsgLoop(GuiWindow *ModalWin)
  5084.     {
  5085.    unsigned long signals;
  5086.     ListBox *SelectedLB = NULL;
  5087.     Frame *FrameDragPtr = NULL;
  5088.     Frame *FrameDownPtr = NULL;
  5089.  
  5090.     stModalWin = ModalWin;
  5091.  
  5092.     if (ModalWin)
  5093.         {
  5094.         /*    On an A500 (unlike newer Amigas) if a new window is opened when a string gadget is active,
  5095.             the string gadget will remain active and the new window won't get activated.  This code solves
  5096.             that problem and although it is unnecessary on newer Amigas it doesn't do any harm. */
  5097.         DeactivateUnknownEditBox();
  5098.         ActivateWindow(ModalWin->Win);
  5099.         }
  5100.  
  5101.    AbortAllMessages();                 /* Abort IO for windows opened before GuiLoop started */
  5102.     ListBoxKeyPress = 0;
  5103.    Stop = GUI_CONTINUE;
  5104.    while (Stop & GUI_CONTINUE) //The user will return GUI_END or GUI_MODAL_END to exit this loop.  GUI_END will also end the program.
  5105.         {
  5106.       QueueAllMessages();
  5107.       Gui.Done = FALSE;
  5108.       ActionPtr = NULL;
  5109.         Action = 0;
  5110.       while (!Gui.Done)
  5111.          {
  5112.             CheckListBoxKeyPress();
  5113.          signals = Wait(Gui.consig | Gui.winsig | Gui.scrsig | UserSigMask);
  5114.  
  5115.             if (signals & Gui.scrsig)
  5116.                 DoScreenSignals(signals, FALSE);
  5117.  
  5118.           if (signals & Gui.consig)
  5119.                 DoConsoleSignals(signals, FALSE);
  5120.  
  5121.          if (signals & Gui.winsig)
  5122.                 DoWindowSignals(signals, FALSE, &SelectedLB, &FrameDragPtr, &FrameDownPtr);
  5123.  
  5124.             if ((signals & UserSigMask) && UserSigFn)
  5125.                 {
  5126.                 Stop = UserSigFn(signals & UserSigMask, UserSigData);
  5127.                 Gui.Done = TRUE;
  5128.                 }
  5129.             } // While (!Gui.Done)
  5130.         DoActions(&FrameDownPtr);
  5131.       AbortAllMessages();
  5132.       } // while (Stop == GUI_CONTINUE)
  5133.     /*    Set Stop back to GUI_CONTINUE so that if this is a modal window exiting, other windows will
  5134.         continue */
  5135.     Stop = GUI_CONTINUE;
  5136.     stModalWin = NULL;
  5137.     }
  5138.  
  5139. void FOXLIB GuiLoop(void)
  5140.    {
  5141.     WinMsgLoop(NULL);
  5142.    }
  5143.  
  5144. void _STD_5001_EndGui(void)
  5145.    {
  5146.    char errortext[100];
  5147.    Diagnostic("EndGui", ENTER, TRUE);
  5148.     while (Gui.FirstUserGadget)
  5149.         UnRegisterGadget(Gui.FirstUserGadget->gad);
  5150.     if (Gui.FirstProgressBar)
  5151.         {
  5152.         while (Gui.FirstProgressBar)
  5153.             DestroyProgressBar(Gui.FirstProgressBar, FALSE);
  5154.         }
  5155.     if (Gui.FirstTimer)
  5156.         DestroyAllTimers();
  5157.     if (Gui.FirstTickBox)
  5158.       DestroyAllTickBoxes(FALSE);
  5159.     if (Gui.FirstRadioButton)
  5160.       DestroyAllRadioButtons(FALSE);
  5161.     if (Gui.FirstListBox)
  5162.       DestroyAllListBoxes(FALSE);
  5163.    if (Gui.GGLfirst)
  5164.       DestroyAllButtons(FALSE);
  5165.    if (Gui.FirstEditBox)
  5166.       {
  5167.       DestroyAllEditBoxes(FALSE);
  5168.       DestroyAllDDListBoxes(FALSE);
  5169.       }
  5170.    if (Gui.FirstOutputBox)
  5171.       DestroyAllOutputBoxes(FALSE);
  5172.     if (Gui.FirstFrame)
  5173.         DestroyAllFrames(FALSE);
  5174.    if (Gui.GWLfirst)
  5175.       CloseAllWindows();
  5176.     if (Gui.FirstScr)
  5177.       {
  5178.       CloseAllGuiScreens();
  5179.         if (Gui.FirstScr) // Failed to close them all.
  5180.             SetLastErr("Failed to close FoxGui Screen(s).");
  5181.       }
  5182.     if (RKCevent)
  5183.         free(RKCevent);
  5184.     if (RKCbuffer)
  5185.         free(RKCbuffer);
  5186.    if (Gui.NumAllocs != 0)
  5187.       {
  5188.       sprintf(errortext, "%d Memory allocations not freed.", Gui.NumAllocs);
  5189.       SetLastErr(errortext);
  5190.       }
  5191.     if (ChipMemForPointer) FreeMem(ChipMemForPointer, sizeof(waitPointer));
  5192.     if (ChipMemForDragPointer) FreeMem(ChipMemForDragPointer, sizeof(GuiDragPointer));
  5193.     if (GuiFont.ta_Name)
  5194.         GuiFree(GuiFont.ta_Name);
  5195.     if (IFFParseBase)
  5196.         CloseLibrary((struct Library *) IFFParseBase);
  5197.     CloseLibrary(LayersBase);
  5198.     CloseLibrary((struct Library *) GfxBase);
  5199.     if (ConsoleDevice)
  5200.         {
  5201.         CloseDevice((struct IORequest *) &ioreq);
  5202.         ConsoleDevice = NULL;
  5203.         }
  5204.     CloseLibrary((struct Library *) IntuitionBase);
  5205.    Diagnostic("EndGui", EXIT, TRUE);
  5206.    }
  5207.